Skip to content

Commit

Permalink
Allow templates in custom_paths & custom_commands sanity-check ar…
Browse files Browse the repository at this point in the history
…guments

E.g. for Python packages we (almost) always want to check for
`lib/python%(pyshortver)s` and potentially add additional paths from
EasyConfigs.
Currently a workaround is used that sets the parameter in the easyconfig
when it isn't set already which is against the semantics of `enhance_sanity_check`.
This change allows this in a trivial way.
  • Loading branch information
Flamefire committed Oct 11, 2024
1 parent ea8db4d commit 93db711
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 2 deletions.
4 changes: 2 additions & 2 deletions easybuild/framework/easyblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -3362,7 +3362,7 @@ def _sanity_check_step_common(self, custom_paths, custom_commands):
# if no sanity_check_paths are specified in easyconfig,
# we fall back to the ones provided by the easyblock via custom_paths
if custom_paths:
paths = custom_paths
paths = self.cfg.resolve_template(custom_paths)
self.log.info("Using customized sanity check paths: %s", paths)
# if custom_paths is empty, we fall back to a generic set of paths:
# non-empty bin/ + /lib or /lib64 directories
Expand Down Expand Up @@ -3412,7 +3412,7 @@ def _sanity_check_step_common(self, custom_paths, custom_commands):
self.log.info("Using (only) sanity check commands specified by easyconfig file: %s", commands)
else:
if custom_commands:
commands = custom_commands
commands = self.cfg.resolve_template(custom_commands)
self.log.info("Using customised sanity check commands: %s", commands)
else:
commands = []
Expand Down
23 changes: 23 additions & 0 deletions test/framework/easyconfigs/test_ecs/p/Python/Python-2.7.15.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
easyblock = 'ConfigureMake'

name = 'Python'
version = '2.7.15'

homepage = 'http://python.org/'
description = """Python is a programming language that lets you work more quickly and integrate your systems
more effectively."""

toolchain = SYSTEM

source_urls = ['http://www.python.org/ftp/%(namelower)s/%(version)s/']
sources = [SOURCE_TGZ]

# This just serves to have a Python as a dependency to test e.g. the Python version templates
# So all dependencies and extensions are removed
dependencies = []

osdependencies = []

exts_list = []

moduleclass = 'lang'
23 changes: 23 additions & 0 deletions test/framework/easyconfigs/test_ecs/p/Python/Python-3.7.2.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
easyblock = 'ConfigureMake'

name = 'Python'
version = '3.7.2'

homepage = 'http://python.org/'
description = """Python is a programming language that lets you work more quickly and integrate your systems
more effectively."""

toolchain = SYSTEM

source_urls = ['http://www.python.org/ftp/%(namelower)s/%(version)s/']
sources = [SOURCE_TGZ]

# This just serves to have a Python as a dependency to test e.g. the Python version templates
# So all dependencies and extensions are removed
dependencies = []

osdependencies = []

exts_list = []

moduleclass = 'lang'
Binary file not shown.
93 changes: 93 additions & 0 deletions test/framework/toy_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,99 @@ def test_toy_build_enhanced_sanity_check(self):

del sys.modules['easybuild.easyblocks.toy']

def test_toy_build_enhanced_sanity_check_templated_multi_dep(self):
"""Test enhancing of sanity check by easyblocks with templates and in the presence of multi_deps."""

# if toy easyblock was imported, get rid of corresponding entry in sys.modules,
# to avoid that it messes up the use of --include-easyblocks=toy.py below...
if 'easybuild.easyblocks.toy' in sys.modules:
del sys.modules['easybuild.easyblocks.toy']

test_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)))
toy_ec = os.path.join(test_dir, 'easyconfigs', 'test_ecs', 't', 'toy', 'toy-0.0.eb')
toy_ec_txt = read_file(toy_ec)

test_ec = os.path.join(self.test_prefix, 'test.eb')

# get rid of custom sanity check paths in test easyconfig
regex = re.compile(r'^sanity_check_paths\s*=\s*{[^}]+}', re.M)
test_ec_txt = regex.sub('', toy_ec_txt)
self.assertNotIn('sanity_check_', test_ec_txt)

test_ec_txt += "\nmulti_deps = {'Python': ['3.7.2', '2.7.15']}"
write_file(test_ec, test_ec_txt)

# create custom easyblock for toy that has a custom sanity_check_step
toy_easyblock = os.path.join(test_dir, 'sandbox', 'easybuild', 'easyblocks', 't', 'toy.py')

toy_easyblock_txt = read_file(toy_easyblock)

toy_custom_sanity_check_step = textwrap.dedent("""
# Add to class to indent
def sanity_check_step(self):
paths = {
'files': ['bin/python%(pyshortver)s'],
'dirs': ['lib/py-%(pyshortver)s'],
}
cmds = ['python%(pyshortver)s']
return super(EB_toy, self).sanity_check_step(custom_paths=paths, custom_commands=cmds)
""")
test_toy_easyblock = os.path.join(self.test_prefix, 'toy.py')
write_file(test_toy_easyblock, toy_easyblock_txt + toy_custom_sanity_check_step)

eb_args = [
'--extended-dry-run',
'--include-easyblocks=%s' % test_toy_easyblock,
]

# by default, sanity check commands & paths specified by easyblock are used
with self.mocked_stdout_stderr():
self.test_toy_build(ec_file=test_ec, extra_args=eb_args, verify=False, testing=False, raise_error=True)
stdout = self.get_stdout()
# Cut output to start of the toy-ec, after the Python installations
stdout = stdout[stdout.index(test_ec):]

pattern_template = textwrap.dedent(r"""
Sanity check paths - file.*
\s*\* bin/python{pyshortver}
Sanity check paths - \(non-empty\) directory.*
\s*\* lib/py-{pyshortver}
Sanity check commands
\s*\* python{pyshortver}
""")
for pyshortver in ('2.7', '3.7'):
regex = re.compile(pattern_template.format(pyshortver=pyshortver), re.M)
self.assertTrue(regex.search(stdout), "Pattern '%s' should be found in: %s" % (regex.pattern, stdout))

# Enhance sanity check by extra paths to check for, the ones from the easyblock should be kept
test_ec_txt += textwrap.dedent("""
enhance_sanity_check = True
sanity_check_paths = {
'files': ['bin/pip%(pyshortver)s'],
'dirs': ['bin'],
}
""")
write_file(test_ec, test_ec_txt)
with self.mocked_stdout_stderr():
self.test_toy_build(ec_file=test_ec, extra_args=eb_args, verify=False, testing=False, raise_error=True)
stdout = self.get_stdout()
# Cut output to start of the toy-ec, after the Python installations
stdout = stdout[stdout.index(test_ec):]

pattern_template = textwrap.dedent(r"""
Sanity check paths - file.*
\s*\* bin/pip{pyshortver}
\s*\* bin/python{pyshortver}
Sanity check paths - \(non-empty\) directory.*
\s*\* bin
\s*\* lib/py-{pyshortver}
Sanity check commands
\s*\* python{pyshortver}
""")
for pyshortver in ('2.7', '3.7'):
regex = re.compile(pattern_template.format(pyshortver=pyshortver), re.M)
self.assertTrue(regex.search(stdout), "Pattern '%s' should be found in: %s" % (regex.pattern, stdout))

def test_toy_dumped_easyconfig(self):
""" Test dumping of file in eb_filerepo in both .eb and .yeb format """
filename = 'toy-0.0'
Expand Down

0 comments on commit 93db711

Please sign in to comment.