From 30046af97b3b4313ca1ea1d992c058b5ef1bab86 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Tue, 14 May 2024 15:37:22 +0200 Subject: [PATCH] Fix resolved values in case of failure When the value cannot be resolved usually the original value is returned. However if it contains `%` signs there will be an escape step and that escaped value is returned. That makes it impossible to have values which can only later be resolved, like `cd %(startdir)s` in extensions which would become `cd %%(startdir)s` on the first resolve-attempt. --- easybuild/framework/easyconfig/easyconfig.py | 2 ++ test/framework/easyconfig.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/easybuild/framework/easyconfig/easyconfig.py b/easybuild/framework/easyconfig/easyconfig.py index 1b28cba328..63b97820bf 100644 --- a/easybuild/framework/easyconfig/easyconfig.py +++ b/easybuild/framework/easyconfig/easyconfig.py @@ -2026,12 +2026,14 @@ def resolve_template(value, tmpl_dict): # '%(name)s' -> '%(name)s' # '%%(name)s' -> '%%(name)s' if '%' in value: + orig_value = value value = re.sub(re.compile(r'(%)(?!%*\(\w+\)s)'), r'\1\1', value) try: value = value % tmpl_dict except KeyError: _log.warning("Unable to resolve template value %s with dict %s", value, tmpl_dict) + value = orig_value # Undo "%"-escaping else: # this block deals with references to objects and returns other references # for reading this is ok, but for self['x'] = {} diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index be780a811b..cd83dd7ca3 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -3663,6 +3663,9 @@ def test_resolve_template(self): ('%%(name)s', '%(name)s'), ('%%%(name)s', '%FooBar'), ('%%%%(name)s', '%%(name)s'), + # It doesn't matter what is resolved + ('%%(invalid)s', '%(invalid)s'), + ('%%%%(invalid)s', '%%(invalid)s'), ) for value, expected in values: self.assertEqual(resolve_template(value, tmpl_dict), expected) @@ -3671,6 +3674,10 @@ def test_resolve_template(self): expected += ' FooBar' self.assertEqual(resolve_template(value, tmpl_dict), expected) + # On unknown values the value is returned unchanged + for value in ('%(invalid)s', '%(name)s %(invalid)s', '%%%(invalid)s', '% %(invalid)s', '%s %(invalid)s'): + self.assertEqual(resolve_template(value, tmpl_dict), value) + def test_det_subtoolchain_version(self): """Test det_subtoolchain_version function""" _, all_tc_classes = search_toolchain('')