diff --git a/easybuild/framework/easyconfig/tools.py b/easybuild/framework/easyconfig/tools.py index 2e548298ff..7919352964 100644 --- a/easybuild/framework/easyconfig/tools.py +++ b/easybuild/framework/easyconfig/tools.py @@ -478,9 +478,9 @@ def find_related_easyconfigs(path, ec): parsed_version = LooseVersion(version).version version_patterns = [version] # exact version match if len(parsed_version) >= 2: - version_patterns.append(r'%s\.%s\.\w+' % tuple(parsed_version[:2])) # major/minor version match + version_patterns.append(r'%s\.%s(\.\w+|(?![\d.]))' % tuple(parsed_version[:2])) # major/minor version match if parsed_version != parsed_version[0]: - version_patterns.append(r'%s\.[\d-]+(\.\w+)*' % parsed_version[0]) # major version match + version_patterns.append(r'%s(\.[\d-]+(\.\w+)*|(?![\d.]))' % parsed_version[0]) # major version match version_patterns.append(r'[\w.]+') # any version regexes = [] diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index e68c2b74a1..d9878a4e41 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -3390,6 +3390,72 @@ def test_find_related_easyconfigs(self): res = [os.path.basename(x) for x in find_related_easyconfigs(test_easyconfigs, ec)] self.assertEqual(res, ['toy-0.0-deps.eb']) + ec['version'] = '1.2.3' + ec['toolchain'] = {'name': 'GCC', 'version': '12'} + + # Create list of files in desired order, so we can remove them one by one + # to check that the search still finds the correct one. + # I.e. the file currently at the top should be returned, + # potentially with equally matching ones, given as values here. + # + # Expected order: + # 1. Same toolchain & version + # 2. Same toolchain, different version + # 3. Any toolchain + # Secondary criteria: + # a. Same toolchain incl. version + # b. Same toolchain, different version + # c. Different toolchain + testcases = { + # 1. Same version + 'toy-1.2.3-GCC-12.eb': [], + 'toy-1.2.3-GCC-11.eb': [], + 'toy-1.2.3-Clang-12.eb': [], + # 2. Different or no patch version + 'toy-1.2.0-GCC-12.eb': ['toy-1.2-GCC-12.eb'], + 'toy-1.2-GCC-12.eb': [], + 'toy-1.2.0-GCC-11.eb': ['toy-1.2-GCC-11.eb'], + 'toy-1.2-GCC-11.eb': [], + 'toy-1.2.0-Clang-12.eb': ['toy-1.2-Clang-12.eb'], + 'toy-1.2-Clang-12.eb': [], + # 3. Different or no minor version, optional patch version + 'toy-1.4.5-GCC-12.eb': ['toy-1.4-GCC-12.eb', 'toy-1-GCC-12.eb'], + 'toy-1.4-GCC-12.eb': ['toy-1-GCC-12.eb'], + 'toy-1-GCC-12.eb': [], + 'toy-1.4.5-GCC-11.eb': ['toy-1.4-GCC-11.eb', 'toy-1-GCC-11.eb'], + 'toy-1.4-GCC-11.eb': ['toy-1-GCC-11.eb'], + 'toy-1-GCC-11.eb': [], + 'toy-1.4.5-Clang-12.eb': ['toy-1.4-Clang-12.eb', 'toy-1-Clang-12.eb'], + 'toy-1.4-Clang-12.eb': ['toy-1-Clang-12.eb'], + 'toy-1-Clang-12.eb': [], + # 4 Different major version + 'toy-4.2.3-GCC-12.eb': ['toy-4.2-GCC-12.eb', 'toy-4-GCC-12.eb'], + 'toy-4.2-GCC-12.eb': ['toy-4-GCC-12.eb'], + 'toy-4-GCC-12.eb': [], + 'toy-4-GCC-11.eb': [], + 'toy-4-Clang-12.eb': [], + } + + # Use an empty folder to have full control over existing files + tmp_ec_dir = tempfile.mkdtemp() + files = [] + for filename in testcases: + filepath = os.path.join(tmp_ec_dir, filename) + write_file(filepath, f"name = '{ec['name']}'") + files.append(filepath) + + ec_name = f'{ec.name}-{ec.version}-{ec["toolchain"]["name"]}-{ec["toolchain"]["version"]}' + while files: + result = find_related_easyconfigs(tmp_ec_dir, ec) + # Only show basenames in error + result, files_b = [[os.path.basename(f) for f in cur_files] for cur_files in (result, files)] + # first file in list should be the one found, followed by additional matches + expected = [files_b[0]] + testcases[files_b[0]] + self.assertEqual(result, expected, + msg='Found %s but expected %s when searching for "%s" in %s' + % (result, expected, ec_name, files_b)) + remove_file(files.pop(0)) + # no matches for unknown software name ec['name'] = 'nosuchsoftware' self.assertEqual(find_related_easyconfigs(test_easyconfigs, ec), [])