diff --git a/easybuild/framework/easyblock.py b/easybuild/framework/easyblock.py index d4a75d6be8..b54b74cf03 100644 --- a/easybuild/framework/easyblock.py +++ b/easybuild/framework/easyblock.py @@ -3368,7 +3368,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 @@ -3418,7 +3418,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 = [] diff --git a/test/framework/easyconfigs/test_ecs/p/Python/Python-2.7.15.eb b/test/framework/easyconfigs/test_ecs/p/Python/Python-2.7.15.eb new file mode 100644 index 0000000000..b9f408e3ef --- /dev/null +++ b/test/framework/easyconfigs/test_ecs/p/Python/Python-2.7.15.eb @@ -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' diff --git a/test/framework/easyconfigs/test_ecs/p/Python/Python-3.7.2.eb b/test/framework/easyconfigs/test_ecs/p/Python/Python-3.7.2.eb new file mode 100644 index 0000000000..a61cabbc32 --- /dev/null +++ b/test/framework/easyconfigs/test_ecs/p/Python/Python-3.7.2.eb @@ -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' diff --git a/test/framework/filetools.py b/test/framework/filetools.py index f6dd6fd7ac..9c5126b020 100644 --- a/test/framework/filetools.py +++ b/test/framework/filetools.py @@ -2474,7 +2474,7 @@ def test_index_functions(self): # test with specified path with and without trailing '/'s for path in [test_ecs, test_ecs + '/', test_ecs + '//']: index = ft.create_index(path) - self.assertEqual(len(index), 92) + self.assertEqual(len(index), 94) expected = [ os.path.join('b', 'bzip2', 'bzip2-1.0.6-GCC-4.9.2.eb'), diff --git a/test/framework/sandbox/sources/p/Python/Python-3.7.2.tgz b/test/framework/sandbox/sources/p/Python/Python-3.7.2.tgz new file mode 100644 index 0000000000..a1583ec2c0 Binary files /dev/null and b/test/framework/sandbox/sources/p/Python/Python-3.7.2.tgz differ diff --git a/test/framework/toy_build.py b/test/framework/toy_build.py index 1bd114d9d7..a334eeca7a 100644 --- a/test/framework/toy_build.py +++ b/test/framework/toy_build.py @@ -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'