From fb817327804eb4ee93f92fee8ac70e44a2cd3a93 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 20 Oct 2025 10:08:47 +0200 Subject: [PATCH 1/2] Add templates for patch versions As it is used by some easyconfigs add `version_patch` and `version_minor_patch` templates similar to existing version templates. As some easyconfigs don't have patch versions don't define those templates in this case so access to/use of them fails. --- easybuild/framework/easyconfig/templates.py | 10 ++++++- test/framework/easyconfig.py | 29 ++++++++++++++------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/easybuild/framework/easyconfig/templates.py b/easybuild/framework/easyconfig/templates.py index fccdd58817..b99ffd7802 100644 --- a/easybuild/framework/easyconfig/templates.py +++ b/easybuild/framework/easyconfig/templates.py @@ -52,7 +52,9 @@ 'toolchain_version': 'Toolchain version', 'version_major_minor': "Major.Minor version", 'version_major': 'Major version', + 'version_minor_patch': 'Minor.Patch version', 'version_minor': 'Minor version', + 'version_patch': 'Patch version', } # derived from EasyConfig._config TEMPLATE_NAMES_CONFIG = [ @@ -206,7 +208,9 @@ 'toolchain_ver': 'toolchain_version', 'ver_maj_min': 'version_major_minor', 'ver_maj': 'version_major', + 'ver_min_patch': 'version_minor_patch', 'ver_min': 'version_minor', + 'ver_patch': 'version_patch', 'version_prefix': 'versionprefix', 'version_suffix': 'versionsuffix', } @@ -343,11 +347,15 @@ def template_constant_dict(config, ignore=None, toolchain=None): minor = version[1] template_values['version_minor'] = minor template_values['version_major_minor'] = '.'.join([major, minor]) + if len(version) > 2: + patch = version[2] + template_values['version_patch'] = patch + template_values['version_minor_patch'] = '.'.join([minor, patch]) except IndexError: # if there is no minor version, skip it pass # only go through this once - ignore.extend(['version_major', 'version_minor', 'version_major_minor']) + ignore.extend(name for name in TEMPLATE_NAMES_EASYCONFIG if name.startswith('version_')) elif name.endswith('letter'): # parse first letters diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index 7a07eab449..a4aa90699b 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -566,15 +566,16 @@ def test_extensions_templates(self): # bogus, but useful to check whether this get resolved 'exts_default_options = {"source_urls": [PYPI_SOURCE]}', 'exts_list = [', - ' ("toy", "0.0", {', + ' ("toy", "0.0.1", {', # %(name)s and %(version_major_minor)s should be resolved using name/version of extension (not parent) # %(pymajver)s should get resolved because Python is listed as a (runtime) dep # %(versionsuffix)s should get resolved with value of parent ' "source_tmpl": "%(name)s-%(version_major_minor)s-py%(pymajver)s%(versionsuffix)s.tar.gz",', - ' "patches": ["%(name)s-%(version)s_fix-silly-typo-in-printf-statement.patch"],', + ' "patches": ["%(name)s-%(version_major_minor)s_fix-silly-typo-in-printf-statement.patch"],', # use hacky prebuildopts that is picked up by 'EB_Toy' easyblock, to check whether templates are resolved - ' "prebuildopts": "gcc -O2 %(name)s.c -o toy-%(version)s &&' + - ' mv toy-%(version)s toy # echo installdir is %(installdir)s #",', + ' "prebuildopts": "gcc -O2 %(name)s.c -o toy-%(version_minor_patch)s &&' + + ' mv toy-%(version_minor_patch)s toy # echo installdir is %(installdir)s #",', + ' "postbuildopts": "echo postbuild step for %(name)s-%(version)s",', ' }),', ']', ]) @@ -597,16 +598,15 @@ def test_extensions_templates(self): # check whether template values were resolved correctly in Extension instances that were created/used toy_ext = eb.ext_instances[0] self.assertEqual(os.path.basename(toy_ext.src), 'toy-0.0-py3-test.tar.gz') - patches = [] - for patch in toy_ext.patches: - patches.append(patch['path']) + patches = [patch['path'] for patch in toy_ext.patches] self.assertEqual(patches, [os.path.join(self.test_prefix, toy_patch_fn)]) # define actual installation dir pi_installdir = os.path.join(self.test_installpath, 'software', 'pi', '3.14-test') - expected_prebuildopts = 'gcc -O2 toy.c -o toy-0.0 && mv toy-0.0 toy # echo installdir is %s #' % pi_installdir + expected_prebuildopts = 'gcc -O2 toy.c -o toy-0.1 && mv toy-0.1 toy # echo installdir is %s #' % pi_installdir expected = { 'patches': ['toy-0.0_fix-silly-typo-in-printf-statement.patch'], 'prebuildopts': expected_prebuildopts, + 'postbuildopts': "echo postbuild step for toy-0.0.1", 'source_tmpl': 'toy-0.0-py3-test.tar.gz', 'source_urls': ['https://pypi.python.org/packages/source/t/toy'], } @@ -3747,10 +3747,21 @@ def test_template_constant_dict(self): 'version': '1.2.3', 'version_major': '1', 'version_major_minor': '1.2', - 'version_minor': '2' + 'version_minor': '2', + 'version_minor_patch': '2.3', + 'version_patch': '3', } self.assertEqual(res, expected) + # No patch version makes the templates undefined + ext_dict['version'] = '1.2' + res = template_constant_dict(ext_dict) + + del expected['version_minor_patch'] + del expected['version_patch'] + expected['version'] = '1.2' + self.assertEqual(res, expected) + def test_parse_deps_templates(self): """Test whether handling of templates defined by dependencies is done correctly.""" test_ecs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs') From 8731fdce3624069322392906c8f76528291f4246 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 20 Oct 2025 10:20:48 +0200 Subject: [PATCH 2/2] Also add `version_major_minor_patch` template Used for e.g. CUDA related ECs. --- easybuild/framework/easyconfig/templates.py | 3 +++ test/framework/easyconfig.py | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/easybuild/framework/easyconfig/templates.py b/easybuild/framework/easyconfig/templates.py index b99ffd7802..36be6a56ea 100644 --- a/easybuild/framework/easyconfig/templates.py +++ b/easybuild/framework/easyconfig/templates.py @@ -50,6 +50,7 @@ 'nameletter': 'First letter of software name', 'toolchain_name': 'Toolchain name', 'toolchain_version': 'Toolchain version', + 'version_major_minor_patch': "Major.Minor.Patch version", 'version_major_minor': "Major.Minor version", 'version_major': 'Major version', 'version_minor_patch': 'Minor.Patch version', @@ -206,6 +207,7 @@ 'r_short_ver': 'rshortver', 'r_ver': 'rver', 'toolchain_ver': 'toolchain_version', + 'ver_maj_min_patch': 'version_major_minor_patch', 'ver_maj_min': 'version_major_minor', 'ver_maj': 'version_major', 'ver_min_patch': 'version_minor_patch', @@ -351,6 +353,7 @@ def template_constant_dict(config, ignore=None, toolchain=None): patch = version[2] template_values['version_patch'] = patch template_values['version_minor_patch'] = '.'.join([minor, patch]) + template_values['version_major_minor_patch'] = '.'.join([major, minor, patch]) except IndexError: # if there is no minor version, skip it pass diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index a4aa90699b..627741469b 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -3723,7 +3723,7 @@ def test_template_constant_dict(self): # also check result of template_constant_dict when dict representing extension is passed ext_dict = { 'name': 'foo', - 'version': '1.2.3', + 'version': '1.2.3.42', 'options': { 'source_urls': ['https://example.com'], 'source_tmpl': '%(name)s-%(version)s.tar.gz', @@ -3744,9 +3744,10 @@ def test_template_constant_dict(self): 'rpath_enabled': rpath, 'software_commit': '', 'sysroot': '', - 'version': '1.2.3', + 'version': '1.2.3.42', 'version_major': '1', 'version_major_minor': '1.2', + 'version_major_minor_patch': '1.2.3', 'version_minor': '2', 'version_minor_patch': '2.3', 'version_patch': '3', @@ -3756,7 +3757,9 @@ def test_template_constant_dict(self): # No patch version makes the templates undefined ext_dict['version'] = '1.2' res = template_constant_dict(ext_dict) + res.pop('arch') + del expected['version_major_minor_patch'] del expected['version_minor_patch'] del expected['version_patch'] expected['version'] = '1.2'