Skip to content

Commit f4b578f

Browse files
authored
Merge branch 'easybuilders:develop' into extension-sanity-check-commands
2 parents 4b556af + 825f842 commit f4b578f

File tree

33 files changed

+416
-117
lines changed

33 files changed

+416
-117
lines changed

.github/workflows/linting.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- name: install Python packages
3030
run: |
3131
pip install --upgrade pip
32-
pip install --upgrade flake8
32+
pip install --upgrade flake8 flake8-comprehensions
3333
3434
- name: Run flake8 to verify PEP8-compliance of Python code
3535
run: |

.github/workflows/unit_tests.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
outputs:
1616
lmod8: Lmod-8.7.65
17+
lmod9: Lmod-9.0
1718
modules4: modules-4.5.3
1819
modules5: modules-5.3.1
1920
steps:
@@ -46,12 +47,17 @@ jobs:
4647
modules_tool: ${{needs.setup.outputs.lmod8}}
4748
- python: '3.13'
4849
modules_tool: ${{needs.setup.outputs.lmod8}}
50+
- python: '3.14'
51+
modules_tool: ${{needs.setup.outputs.lmod8}}
52+
# also test with Lmod 9.x
53+
- python: '3.9'
54+
modules_tool: ${{needs.setup.outputs.lmod9}}
4955
fail-fast: false
5056
steps:
5157
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
5258

5359
- name: set up Python
54-
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
60+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
5561
with:
5662
python-version: ${{matrix.python}}
5763
architecture: x64
@@ -150,7 +156,10 @@ jobs:
150156
# also pick up changes to $PATH set by sourcing $MOD_INIT
151157
export PREFIX=/tmp/$USER/$GITHUB_SHA
152158
export PATH=$PREFIX/bin:$(cat $HOME/path)
153-
export PYTHONPATH=$PREFIX/lib/python${{matrix.python}}/site-packages:$PYTHONPATH
159+
export PYTHONPATH=$PREFIX/lib/python$(echo ${{matrix.python}} | cut -f1,2 -d'.')/site-packages:$PYTHONPATH
160+
echo "PYTHONPATH=$PYTHONPATH"
161+
ls $(echo $PYTHONPATH | cut -f1:)
162+
python3 -m easybuild.main --version
154163
eb --version
155164
# tell EasyBuild which modules tool is available
156165
if [[ ${{matrix.modules_tool}} =~ ^modules- ]]; then

contrib/hooks/bumpOpenSSL.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS
2+
3+
4+
def parse_hook(ec, *args, **kwargs):
5+
"""
6+
EasyBuild parse hook for EL9+ compatibility
7+
"""
8+
# looks like [('zlib', '1.2.13'), ('OpenSSL', '1.1', '', {'name': 'system', 'version': 'system'})]
9+
raw_deps = ec['dependencies'] if 'dependencies' in ec else []
10+
11+
# Check if OpenSSL is in any dependency tuple's first element
12+
openssl_found = any(dep[0] == 'OpenSSL' for dep in raw_deps)
13+
14+
# if found, replace its version - second element in the tuple with '3'.
15+
if openssl_found:
16+
print(f"[openssl1->3 hook] OpenSSL found in dependencies of {ec['name']}, replacing with OpenSSL 3")
17+
for i, dep in enumerate(raw_deps):
18+
if dep[0] == 'OpenSSL' and dep[1] == '1.1':
19+
raw_deps[i] = ('OpenSSL', '3', '', EASYCONFIG_CONSTANTS['SYSTEM'][0])
20+
break
21+
22+
else:
23+
# no need to do anything
24+
return
25+
26+
ec['dependencies'] = raw_deps

easybuild/base/fancylogger.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def thread_name():
435435
"""
436436
returns the current threads name
437437
"""
438-
return threading.currentThread().getName()
438+
return threading.current_thread().name
439439

440440

441441
def getLogger(name=None, fname=False, clsname=False, fancyrecord=None):
@@ -577,8 +577,8 @@ def logToFile(filename, enable=True, filehandler=None, name=None, max_bytes=MAX_
577577
'mode': 'a',
578578
'maxBytes': max_bytes,
579579
'backupCount': backup_count,
580+
'encoding': 'utf-8',
580581
}
581-
handleropts['encoding'] = 'utf-8'
582582
# logging to a file is going to create the file later on, so let's try to be helpful and create the path if needed
583583
directory = os.path.dirname(filename)
584584
if not os.path.exists(directory):
@@ -783,7 +783,7 @@ def getAllExistingLoggers():
783783
"""
784784
# not-so-well documented manager (in 2.6 and later)
785785
# return list of (name,logger) tuple
786-
return [x for x in logging.Logger.manager.loggerDict.items()] + [(logging.root.name, logging.root)]
786+
return list(logging.Logger.manager.loggerDict.items()) + [(logging.root.name, logging.root)]
787787

788788

789789
def getAllNonFancyloggers():

easybuild/base/wrapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def proxy(self, *args): # pylint:disable=unused-argument
3939
# create proxies for wrapped object's double-underscore attributes
4040
type.__init__(cls, name, bases, dct)
4141
if cls.__wraps__:
42-
ignore = set("__%s__" % n for n in cls.__ignore__.split())
42+
ignore = {"__%s__" % n for n in cls.__ignore__.split()}
4343
for name in dir(cls.__wraps__):
4444
if name.startswith("__"):
4545
if name not in ignore and name not in dct:

easybuild/framework/easyblock.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,7 +2125,8 @@ def install_extensions_sequential(self, install=True):
21252125
self.log.debug("List of loaded modules: %s", self.modules_tool.list())
21262126
# don't reload modules for toolchain, there is no need
21272127
# since they will be loaded already by the fake module
2128-
ext.toolchain.prepare(onlymod=self.cfg['onlytcmod'], silent=True, loadmod=False,
2128+
ext.toolchain.prepare(onlymod=self.cfg['onlytcmod'], deps=self.cfg.dependencies(),
2129+
silent=True, loadmod=False,
21292130
rpath_filter_dirs=self.rpath_filter_dirs,
21302131
rpath_include_dirs=self.rpath_include_dirs,
21312132
rpath_wrappers_dir=self.rpath_wrappers_dir)
@@ -2287,7 +2288,8 @@ def update_exts_progress_bar_helper(running_exts, progress_size):
22872288
with self.fake_module_environment(with_build_deps=True):
22882289
# don't reload modules for toolchain, there is no
22892290
# need since they will be loaded by the fake module
2290-
ext.toolchain.prepare(onlymod=self.cfg['onlytcmod'], silent=True, loadmod=False,
2291+
ext.toolchain.prepare(onlymod=self.cfg['onlytcmod'], deps=self.cfg.dependencies(),
2292+
silent=True, loadmod=False,
22912293
rpath_filter_dirs=self.rpath_filter_dirs,
22922294
rpath_include_dirs=self.rpath_include_dirs,
22932295
rpath_wrappers_dir=self.rpath_wrappers_dir)
@@ -2742,7 +2744,8 @@ def check_checksums_for(self, ent, sub='', source_cnt=None):
27422744
try:
27432745
sources = ent.get('sources', [])
27442746
data_sources = ent.get('data_sources', [])
2745-
patches = ent.get('patches', []) + ent.get('postinstallpatches', [])
2747+
patches = ent.get('patches', []) + ent.get(ALTERNATIVE_EASYCONFIG_PARAMETERS['post_install_patches'],
2748+
ent.get('post_install_patches', []))
27462749
checksums = ent.get('checksums', [])
27472750
except EasyBuildError:
27482751
if isinstance(ent, EasyConfig):

easybuild/framework/easyconfig/easyconfig.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ def det_subtoolchain_version(current_tc, subtoolchain_names, optional_toolchains
261261

262262
for subtoolchain_name in subtoolchain_names:
263263

264-
uniq_subtc_versions = set([subtc['version'] for subtc in cands if subtc['name'] == subtoolchain_name])
264+
uniq_subtc_versions = {subtc['version'] for subtc in cands if subtc['name'] == subtoolchain_name}
265265

266266
# system toolchain: bottom of the hierarchy
267267
if is_system_toolchain(subtoolchain_name):
@@ -318,8 +318,8 @@ def get_toolchain_hierarchy(parent_toolchain, incl_capabilities=False):
318318
# obtain list of all possible subtoolchains
319319
_, all_tc_classes = search_toolchain('')
320320
subtoolchains = {tc_class.NAME: getattr(tc_class, 'SUBTOOLCHAIN', None) for tc_class in all_tc_classes}
321-
optional_toolchains = set(tc_class.NAME for tc_class in all_tc_classes if getattr(tc_class, 'OPTIONAL', False))
322-
composite_toolchains = set(tc_class.NAME for tc_class in all_tc_classes if len(tc_class.__bases__) > 1)
321+
optional_toolchains = {tc_class.NAME for tc_class in all_tc_classes if getattr(tc_class, 'OPTIONAL', False)}
322+
composite_toolchains = {tc_class.NAME for tc_class in all_tc_classes if len(tc_class.__bases__) > 1}
323323

324324
# the parent toolchain is at the top of the hierarchy,
325325
# we need a copy so that adding capabilities (below) doesn't affect the original object
@@ -1219,14 +1219,16 @@ def dependencies(self, build_only=False, runtime_only=False):
12191219

12201220
return retained_deps
12211221

1222-
def dependency_names(self, build_only=False):
1222+
def dependency_names(self, build_only=False, runtime_only=False):
12231223
"""
12241224
Return a set of names of all (direct) dependencies after filtering.
12251225
Iterable builddependencies are flattened when not iterating.
12261226
12271227
:param build_only: only return build dependencies, discard others
1228+
:param runtime_only: only return runtime dependencies, discard others
12281229
"""
1229-
return {dep['name'] for dep in self.dependencies(build_only=build_only) if dep['name']}
1230+
return {dep['name'] for dep in self.dependencies(build_only=build_only, runtime_only=runtime_only)
1231+
if dep['name']}
12301232

12311233
def builddependencies(self):
12321234
"""
@@ -1279,7 +1281,7 @@ def toolchain(self):
12791281
else:
12801282
self.log.debug("Found easyconfig for toolchain %s version %s: %s", tcname, tcversion, tc_ecfile)
12811283
tc_ec = process_easyconfig(tc_ecfile)[0]
1282-
tcdeps = tc_ec['ec'].dependencies()
1284+
tcdeps = tc_ec['ec'].dependencies(runtime_only=True)
12831285
self.log.debug("Toolchain dependencies based on easyconfig: %s", tcdeps)
12841286

12851287
self._toolchain = get_toolchain(self['toolchain'], self['toolchainopts'],

easybuild/framework/easyconfig/templates.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,12 @@
5050
'nameletter': 'First letter of software name',
5151
'toolchain_name': 'Toolchain name',
5252
'toolchain_version': 'Toolchain version',
53+
'version_major_minor_patch': "Major.Minor.Patch version",
5354
'version_major_minor': "Major.Minor version",
5455
'version_major': 'Major version',
56+
'version_minor_patch': 'Minor.Patch version',
5557
'version_minor': 'Minor version',
58+
'version_patch': 'Patch version',
5659
}
5760
# derived from EasyConfig._config
5861
TEMPLATE_NAMES_CONFIG = [
@@ -204,9 +207,12 @@
204207
'r_short_ver': 'rshortver',
205208
'r_ver': 'rver',
206209
'toolchain_ver': 'toolchain_version',
210+
'ver_maj_min_patch': 'version_major_minor_patch',
207211
'ver_maj_min': 'version_major_minor',
208212
'ver_maj': 'version_major',
213+
'ver_min_patch': 'version_minor_patch',
209214
'ver_min': 'version_minor',
215+
'ver_patch': 'version_patch',
210216
'version_prefix': 'versionprefix',
211217
'version_suffix': 'versionsuffix',
212218
}
@@ -343,11 +349,16 @@ def template_constant_dict(config, ignore=None, toolchain=None):
343349
minor = version[1]
344350
template_values['version_minor'] = minor
345351
template_values['version_major_minor'] = '.'.join([major, minor])
352+
if len(version) > 2:
353+
patch = version[2]
354+
template_values['version_patch'] = patch
355+
template_values['version_minor_patch'] = '.'.join([minor, patch])
356+
template_values['version_major_minor_patch'] = '.'.join([major, minor, patch])
346357
except IndexError:
347358
# if there is no minor version, skip it
348359
pass
349360
# only go through this once
350-
ignore.extend(['version_major', 'version_minor', 'version_major_minor'])
361+
ignore.extend(name for name in TEMPLATE_NAMES_EASYCONFIG if name.startswith('version_'))
351362

352363
elif name.endswith('letter'):
353364
# parse first letters

easybuild/framework/easyconfig/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ def _to_checksum(checksum, list_level=0, allow_dict=True):
541541
# When we already are in a tuple no further recursion is allowed -> set list_level very high
542542
return tuple(_to_checksum(x, list_level=99, allow_dict=allow_dict) for x in checksum)
543543
else:
544-
return list(_to_checksum(x, list_level=list_level+1, allow_dict=allow_dict) for x in checksum)
544+
return [_to_checksum(x, list_level=list_level+1, allow_dict=allow_dict) for x in checksum]
545545
elif isinstance(checksum, dict) and allow_dict:
546546
return {key: _to_checksum(value, allow_dict=False) for key, value in checksum.items()}
547547

easybuild/main.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import sys
4646
import tempfile
4747
import traceback
48+
from datetime import datetime
4849

4950
# IMPORTANT this has to be the first easybuild import as it customises the logging
5051
# expect missing log output when this not the case!
@@ -84,6 +85,7 @@
8485
from easybuild.tools.repository.repository import init_repository
8586
from easybuild.tools.systemtools import check_easybuild_deps
8687
from easybuild.tools.testing import create_test_report, overall_test_report, regtest, session_state
88+
from easybuild.tools.utilities import time2str
8789
from easybuild.tools.version import EASYBLOCKS_VERSION, FRAMEWORK_VERSION, UNKNOWN_EASYBLOCKS_VERSION
8890
from easybuild.tools.version import different_major_versions
8991

@@ -585,6 +587,7 @@ def process_eb_args(eb_args, eb_go, cfg_settings, modtool, testing, init_session
585587
return True
586588

587589
# build software, will exit when errors occurs (except when testing)
590+
start_time = datetime.now()
588591
if not testing or (testing and do_build):
589592
exit_on_failure = not (options.dump_test_report or options.upload_test_report)
590593

@@ -601,7 +604,8 @@ def process_eb_args(eb_args, eb_go, cfg_settings, modtool, testing, init_session
601604
success_msg = "Build succeeded "
602605
if build_option('ignore_test_failure'):
603606
success_msg += "(with --ignore-test-failure) "
604-
success_msg += "for %s out of %s" % (correct_builds_cnt, len(ordered_ecs))
607+
success_msg += f"for {correct_builds_cnt} out of {len(ordered_ecs)} "
608+
success_msg += f"(total: {time2str(datetime.now() - start_time)})"
605609

606610
repo = init_repository(get_repository(), get_repositorypath())
607611
repo.cleanup()

0 commit comments

Comments
 (0)