Skip to content

Commit b0544c1

Browse files
committed
Merge branch 'easybuilders:develop' into develop
2 parents 28c9de2 + 9697704 commit b0544c1

File tree

25 files changed

+453
-207
lines changed

25 files changed

+453
-207
lines changed

RELEASE_NOTES

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,68 @@ 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.4.0 (June 2nd 2021)
8+
----------------------
9+
10+
feature release
11+
12+
- various enhancements, including:
13+
- enhance apply_regex_substitutions to allow specifying action to take in case there are no matches (#3440)
14+
- performance improvements for easyconfig parsing and eb startup (#3555)
15+
- add support for downloading easyconfigs from multiple PRs with --from-pr (#3605, #3707, #3708)
16+
- add support for prepending custom library paths in RPATH section via --rpath-override-dirs (#3650)
17+
- allow amending easyconfig parameters which are not the default (#3651)
18+
- update HierarchicalMNS for Intel OneAPI compilers (#3653)
19+
- add support for --sanity-check-only (#3655)
20+
- add support for running commands asynchronously via run_cmd + complete_cmd functions (#3656)
21+
- add support for using oneAPI versions of 'intel' toolchain components (#3665)
22+
- add toolchain definition for gofbf (foss with FlexiBLAS rather than OpenBLAS) (#3666)
23+
- add support for using ARCH constant in easyconfig files (#3670)
24+
- honor keyboard interrupt in 'eb' command (#3674)
25+
- add toolchain definition for Fujitsu toolchain (#3677, #3704, #3712, #3713, #3714, #3717)
26+
- extend sanity check step to check whether specific libraries are not linked into installed binaries/libraries (#3678)
27+
- via banned-linked-shared-libs and required-linked-shared-libs EasyBuild configuration options
28+
- via banned_linked_shared_libs and required_linked_shared_libs methods in toolchain support
29+
- via banned_linked_shared_libs and required_linked_shared_libs methods in easyblock
30+
- via banned_linked_shared_libs and required_linked_shared_libs easyconfig parameters
31+
- add locate_solib function to locate Linux shared libraries (#3682)
32+
- add system agnostic function to locate shared libraries (#3683)
33+
- add update_build_option function to update specific build options after initializing the EasyBuild configuration (#3684)
34+
- allow opting out of recursively unloaded of modules via recursive_module_unload easyconfig parameter (#3689)
35+
- check for correct version values when parsing easystack file (#3693)
36+
- run post-install commands specified for a specific extension (#3696)
37+
- add support for --skip-extensions (#3702)
38+
- include PR title in output produced by --merge-pr (#3706)
39+
- various bug fixes, including:
40+
- avoid metadata greedy behaviour when probing for external module metadata (mostly relevant for integration with Cray Programming Environment) (#3559)
41+
- catch problems early on if --github-user is not specified for --new-pr & co (#3644)
42+
- re-enable write permissions when installing with read-only-installdir (#3649)
43+
- also run sanity check for extensions when using --module-only (#3655)
44+
- improve logging when failing to load class from exts_classmap (#3657)
45+
- fix use of --module-only on existing installations without write permissions (#3659)
46+
- correct help text for subdir-user-modules (#3660)
47+
- avoid picking up easyblocks outside of sandbox in framework tests (#3680)
48+
- use unload/load in ModuleGeneratorLua.swap_module, since 'swap' is not supported by Lmod (#3685)
49+
- update HierarchicalMNS to also return 'Toolchain/<name>/<version>' as $MODULEPATH extension for cpe* Cray toolchains (#3686)
50+
- make EasyConfigParser.get_config_dict return a copy rather than a reference (#3692)
51+
- make sure that $TAPE is unset when using piped tar (#3698)
52+
- fix extending message for changed files in new_pr_from_branch (#3699)
53+
- enhance sched_getaffinity function to avoid early crash when counting available cores on systems with more than 1024 cores (#3701)
54+
- correctly strip extension from filename in extract_cmd and back_up_file functions (#3705)
55+
- other changes:
56+
- deprecate adding a non-existing path to $MODULEPATH (#3637)
57+
- bump cryptography requirement from 3.2.1 to 3.3.2 (#3643, #3648)
58+
- test bootstrap script in separate workflow, and limit test configurations a bit (#3646)
59+
- update setup.py to indicate compatibility with Python 3.8 and 3.9 (#3647)
60+
- replace log_error parameter of which() by on_error (#3661, #3664)
61+
- don't skip sanity check for --module-only --rebuild (#3645)
62+
- move disable_templating function into the EasyConfig class (#3668)
63+
- pin GitPython version for Python<3.6, don't test bootstrap script against Python 3.8/3.9 (#3675)
64+
- tweak foss toolchain definition to switch from OpenBLAS to FlexiBLAS in foss/2021a (#3679)
65+
- suggest missing SSH key when not able to read from remote repository in --check-github (#3681)
66+
- drop support for Python 2.6 (#3715)
67+
68+
769
v4.3.4 (April 9th 2021)
870
-----------------------
971

easybuild/framework/easyblock.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
from easybuild.tools.hooks import BUILD_STEP, CLEANUP_STEP, CONFIGURE_STEP, EXTENSIONS_STEP, FETCH_STEP, INSTALL_STEP
8282
from easybuild.tools.hooks import MODULE_STEP, PACKAGE_STEP, PATCH_STEP, PERMISSIONS_STEP, POSTITER_STEP, POSTPROC_STEP
8383
from easybuild.tools.hooks import PREPARE_STEP, READY_STEP, SANITYCHECK_STEP, SOURCE_STEP, TEST_STEP, TESTCASES_STEP
84-
from easybuild.tools.hooks import load_hooks, run_hook
84+
from easybuild.tools.hooks import MODULE_WRITE, load_hooks, run_hook
8585
from easybuild.tools.run import run_cmd
8686
from easybuild.tools.jenkins import write_to_xml
8787
from easybuild.tools.module_generator import ModuleGeneratorLua, ModuleGeneratorTcl, module_generator, dependencies_for
@@ -144,7 +144,7 @@ def __init__(self, ec):
144144
# keep track of original working directory, so we can go back there
145145
self.orig_workdir = os.getcwd()
146146

147-
# list of pre- and post-step hooks
147+
# dict of all hooks (mapping of name to function)
148148
self.hooks = load_hooks(build_option('hooks'))
149149

150150
# list of patch/source files, along with checksums
@@ -3165,6 +3165,10 @@ def make_module_step(self, fake=False):
31653165
txt += self.make_module_extra()
31663166
txt += self.make_module_footer()
31673167

3168+
hook_txt = run_hook(MODULE_WRITE, self.hooks, args=[self, mod_filepath, txt])
3169+
if hook_txt is not None:
3170+
txt = hook_txt
3171+
31683172
if self.dry_run:
31693173
# only report generating actual module file during dry run, don't mention temporary module files
31703174
if not fake:
@@ -3528,7 +3532,16 @@ def run_all_steps(self, run_test_cases):
35283532
else:
35293533
print_msg("%s..." % descr, log=self.log, silent=self.silent)
35303534
self.current_step = step_name
3531-
self.run_step(step_name, step_methods)
3535+
start_time = datetime.now()
3536+
try:
3537+
self.run_step(step_name, step_methods)
3538+
finally:
3539+
if not self.dry_run:
3540+
step_duration = datetime.now() - start_time
3541+
if step_duration.total_seconds() >= 1:
3542+
print_msg("... (took %s)", time2str(step_duration), log=self.log, silent=self.silent)
3543+
elif self.logdebug or build_option('trace'):
3544+
print_msg("... (took < 1 sec)", log=self.log, silent=self.silent)
35323545

35333546
except StopException:
35343547
pass

easybuild/framework/easyconfig/format/one.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,14 @@ def get_config_dict(self):
135135
# we can't use copy.deepcopy() directly because in Python 2 copying the (irrelevant) __builtins__ key fails...
136136
cfg_copy = {}
137137
for key in cfg:
138-
if key != '__builtins__':
139-
cfg_copy[key] = copy.deepcopy(cfg[key])
138+
# skip special variables like __builtins__, and imported modules (like 'os')
139+
if key != '__builtins__' and "'module'" not in str(type(cfg[key])):
140+
try:
141+
cfg_copy[key] = copy.deepcopy(cfg[key])
142+
except Exception as err:
143+
raise EasyBuildError("Failed to copy '%s' easyconfig parameter: %s" % (key, err))
144+
else:
145+
self.log.debug("Not copying '%s' variable from parsed easyconfig", key)
140146

141147
return cfg_copy
142148

easybuild/framework/easyconfig/tools.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def get_paths_for(subdir=EASYCONFIGS_PKG_SUBDIR, robot_path=None):
307307
return paths
308308

309309

310-
def alt_easyconfig_paths(tmpdir, tweaked_ecs=False, from_pr=False):
310+
def alt_easyconfig_paths(tmpdir, tweaked_ecs=False, from_prs=None):
311311
"""Obtain alternative paths for easyconfig files."""
312312

313313
# paths where tweaked easyconfigs will be placed, easyconfigs listed on the command line take priority and will be
@@ -318,12 +318,13 @@ def alt_easyconfig_paths(tmpdir, tweaked_ecs=False, from_pr=False):
318318
tweaked_ecs_paths = (os.path.join(tmpdir, 'tweaked_easyconfigs'),
319319
os.path.join(tmpdir, 'tweaked_dep_easyconfigs'))
320320

321-
# path where files touched in PR will be downloaded to
322-
pr_path = None
323-
if from_pr:
324-
pr_path = os.path.join(tmpdir, "files_pr%s" % '_'.join(str(pr) for pr in from_pr))
321+
# paths where files touched in PRs will be downloaded to,
322+
# which are picked up via 'pr_paths' build option in fetch_files_from_pr
323+
pr_paths = None
324+
if from_prs:
325+
pr_paths = [os.path.join(tmpdir, 'files_pr%s' % pr) for pr in from_prs]
325326

326-
return tweaked_ecs_paths, pr_path
327+
return tweaked_ecs_paths, pr_paths
327328

328329

329330
def det_easyconfig_paths(orig_paths):
@@ -333,7 +334,7 @@ def det_easyconfig_paths(orig_paths):
333334
:return: list of paths to easyconfig files
334335
"""
335336
try:
336-
from_pr_list = [int(pr_nr) for pr_nr in build_option('from_pr')]
337+
from_prs = [int(x) for x in build_option('from_pr')]
337338
except ValueError:
338339
raise EasyBuildError("Argument to --from-pr must be a comma separated list of PR #s.")
339340

@@ -342,9 +343,11 @@ def det_easyconfig_paths(orig_paths):
342343
# list of specified easyconfig files
343344
ec_files = orig_paths[:]
344345

345-
if from_pr_list is not None:
346+
if from_prs:
346347
pr_files = []
347-
for pr in from_pr_list:
348+
for pr in from_prs:
349+
# path to where easyconfig files should be downloaded is determined via 'pr_paths' build option,
350+
# which corresponds to the list of PR paths returned by alt_easyconfig_paths
348351
pr_files.extend(fetch_easyconfigs_from_pr(pr))
349352

350353
if ec_files:
@@ -620,6 +623,14 @@ def categorize_files_by_type(paths):
620623
# file must exist in order to check whether it's a patch file
621624
elif os.path.isfile(path) and is_patch_file(path):
622625
res['patch_files'].append(path)
626+
elif path.endswith('.patch'):
627+
if not os.path.exists(path):
628+
raise EasyBuildError('File %s does not exist, did you mistype the path?', path)
629+
elif not os.path.isfile(path):
630+
raise EasyBuildError('File %s is expected to be a regular file, but is a folder instead', path)
631+
else:
632+
raise EasyBuildError('%s is not detected as a valid patch file. Please verify its contents!',
633+
path)
623634
else:
624635
# anything else is considered to be an easyconfig file
625636
res['easyconfigs'].append(path)

easybuild/toolchains/compiler/fujitsu.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
:author: Miguel Dias Costa (National University of Singapore)
3131
"""
3232
import os
33+
import re
3334

35+
import easybuild.tools.environment as env
3436
import easybuild.tools.systemtools as systemtools
3537
from easybuild.tools.toolchain.compiler import Compiler, DEFAULT_OPT_LEVEL
3638

@@ -46,9 +48,8 @@ class FujitsuCompiler(Compiler):
4648
COMPILER_MODULE_NAME = [TC_CONSTANT_MODULE_NAME]
4749
COMPILER_FAMILY = TC_CONSTANT_FUJITSU
4850

49-
# make sure fcc is always called in clang compatibility mode
50-
COMPILER_CC = 'fcc -Nclang'
51-
COMPILER_CXX = 'FCC -Nclang'
51+
COMPILER_CC = 'fcc'
52+
COMPILER_CXX = 'FCC'
5253

5354
COMPILER_F77 = 'frt'
5455
COMPILER_F90 = 'frt'
@@ -85,15 +86,31 @@ class FujitsuCompiler(Compiler):
8586
(systemtools.AARCH64, systemtools.ARM): '-mcpu=generic -mtune=generic',
8687
}
8788

89+
def prepare(self, *args, **kwargs):
90+
super(FujitsuCompiler, self).prepare(*args, **kwargs)
91+
92+
# fcc doesn't accept e.g. -std=c++11 or -std=gnu++11, only -std=c11 or -std=gnu11
93+
pattern = r'-std=(gnu|c)\+\+(\d+)'
94+
if re.search(pattern, self.vars['CFLAGS']):
95+
self.log.debug("Found '-std=(gnu|c)++' in CFLAGS, fcc doesn't accept '++' here, removing it")
96+
self.vars['CFLAGS'] = re.sub(pattern, r'-std=\1\2', self.vars['CFLAGS'])
97+
self._setenv_variables()
98+
99+
# make sure the fujitsu module libraries are found (and added to rpath by wrapper)
100+
library_path = os.getenv('LIBRARY_PATH', '')
101+
libdir = os.path.join(os.getenv(TC_CONSTANT_MODULE_VAR), 'lib64')
102+
if libdir not in library_path:
103+
self.log.debug("Adding %s to $LIBRARY_PATH" % libdir)
104+
env.setvar('LIBRARY_PATH', os.pathsep.join([library_path, libdir]))
105+
88106
def _set_compiler_vars(self):
89107
super(FujitsuCompiler, self)._set_compiler_vars()
90108

91109
# enable clang compatibility mode
92-
# moved to compiler constants to make sure it is always used
93-
# self.variables.nappend('CFLAGS', ['Nclang'])
94-
# self.variables.nappend('CXXFLAGS', ['Nclang'])
110+
self.variables.nappend('CFLAGS', ['Nclang'])
111+
self.variables.nappend('CXXFLAGS', ['Nclang'])
95112

96-
# make sure the fujitsu module libraries are found (and added to rpath by wrapper)
113+
# also add fujitsu module library path to LDFLAGS
97114
libdir = os.path.join(os.getenv(TC_CONSTANT_MODULE_VAR), 'lib64')
98115
self.log.debug("Adding %s to $LDFLAGS" % libdir)
99116
self.variables.nappend('LDFLAGS', [libdir])

easybuild/toolchains/fft/fujitsufftw.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,4 @@
3333
class FujitsuFFTW(Fftw):
3434
"""Fujitsu FFTW FFT library"""
3535

36-
FFT_MODULE_NAME = ['FFTW3-sve']
3736
FFTW_API_VERSION = '3'

easybuild/toolchains/fujitsu.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,3 @@ class Fujitsu(Ffmpi, FujitsuFFTW, FujitsuSSL):
3636
"""Compiler toolchain for Fujitsu."""
3737
NAME = 'Fujitsu'
3838
SUBTOOLCHAIN = Ffmpi.NAME
39-
COMPILER_MODULE_NAME = []

easybuild/tools/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
346346
'build_specs',
347347
'command_line',
348348
'external_modules_metadata',
349-
'pr_path',
349+
'pr_paths',
350350
'robot_path',
351351
'valid_module_classes',
352352
'valid_stops',

easybuild/tools/github.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,15 @@ def fetch_files_from_pr(pr, path=None, github_user=None, github_account=None, gi
447447

448448
if path is None:
449449
if github_repo == GITHUB_EASYCONFIGS_REPO:
450-
path = build_option('pr_path')
450+
pr_paths = build_option('pr_paths')
451+
if pr_paths:
452+
# figure out directory for this specific PR (see also alt_easyconfig_paths)
453+
cands = [p for p in pr_paths if p.endswith('files_pr%s' % pr)]
454+
if len(cands) == 1:
455+
path = cands[0]
456+
else:
457+
raise EasyBuildError("Failed to isolate path for PR #%s from list of PR paths: %s", pr, pr_paths)
458+
451459
elif github_repo == GITHUB_EASYBLOCKS_REPO:
452460
path = os.path.join(tempfile.gettempdir(), 'ebs_pr%s' % pr)
453461
else:
@@ -1224,7 +1232,7 @@ def reasons_for_closing(pr_data):
12241232

12251233
robot_paths = build_option('robot_path')
12261234

1227-
pr_files = [path for path in fetch_easyconfigs_from_pr(pr_data['number']) if path.endswith('.eb')]
1235+
pr_files = [p for p in fetch_easyconfigs_from_pr(pr_data['number']) if p.endswith('.eb')]
12281236

12291237
obsoleted = []
12301238
uses_archived_tc = []
@@ -1381,6 +1389,7 @@ def merge_pr(pr):
13811389

13821390
msg = "\n%s/%s PR #%s was submitted by %s, " % (pr_target_account, pr_target_repo, pr, pr_data['user']['login'])
13831391
msg += "you are using GitHub account '%s'\n" % github_user
1392+
msg += "\nPR title: %s\n\n" % pr_data['title']
13841393
print_msg(msg, prefix=False)
13851394
if pr_data['user']['login'] == github_user:
13861395
raise EasyBuildError("Please do not merge your own PRs!")
@@ -1482,17 +1491,17 @@ def add_pr_labels(pr, branch=GITHUB_DEVELOP_BRANCH):
14821491

14831492
download_repo_path = download_repo(branch=branch, path=tmpdir)
14841493

1485-
pr_files = [path for path in fetch_easyconfigs_from_pr(pr) if path.endswith('.eb')]
1494+
pr_files = [p for p in fetch_easyconfigs_from_pr(pr) if p.endswith('.eb')]
14861495

14871496
file_info = det_file_info(pr_files, download_repo_path)
14881497

14891498
pr_target_account = build_option('pr_target_account')
14901499
github_user = build_option('github_user')
14911500
pr_data, _ = fetch_pr_data(pr, pr_target_account, pr_target_repo, github_user)
1492-
pr_labels = [label['name'] for label in pr_data['labels']]
1501+
pr_labels = [x['name'] for x in pr_data['labels']]
14931502

14941503
expected_labels = det_pr_labels(file_info, pr_target_repo)
1495-
missing_labels = [label for label in expected_labels if label not in pr_labels]
1504+
missing_labels = [x for x in expected_labels if x not in pr_labels]
14961505

14971506
dry_run = build_option('dry_run') or build_option('extended_dry_run')
14981507

0 commit comments

Comments
 (0)