Skip to content

Commit 2e3b348

Browse files
committed
Avoid processing the same EasyConfig multiple times
When passing the same EasyConfig file multiple times on the commandline it will be parsed once and put into a cache. Every future call will get the same `EasyConfig` instance so any modification to it will be reflected in all future uses of supposedly "freshly parsed EasyConfigs". This leads to confusing failures when trying to build the same file twice which is likely a mistake anyway, especially when one file is a symlink to another one passed too. So just make sure each physical file is parsed only once.
1 parent 5fd677b commit 2e3b348

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

easybuild/framework/easyconfig/tools.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,15 @@ def parse_easyconfigs(paths, validate=True):
404404
"""
405405
easyconfigs = []
406406
generated_ecs = False
407+
parsed_paths = []
407408

408409
for (path, generated) in paths:
410+
# Avoid processing the same file multiple times
409411
path = os.path.abspath(path)
412+
if any(os.path.samefile(path, p) for p in parsed_paths):
413+
continue
414+
parsed_paths.append(path)
415+
410416
# keep track of whether any files were generated
411417
generated_ecs |= generated
412418
if not os.path.exists(path):

test/framework/easyconfig.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,32 @@ def test_tweaking(self):
737737
# cleanup
738738
os.remove(tweaked_fn)
739739

740+
def test_parse_easyconfig(self):
741+
"""Test parse_easyconfig function"""
742+
self.contents = textwrap.dedent("""
743+
easyblock = "ConfigureMake"
744+
name = "PI"
745+
version = "3.14"
746+
homepage = "http://example.com"
747+
description = "test easyconfig"
748+
toolchain = SYSTEM
749+
""")
750+
self.prep()
751+
ecs, gen_ecs = parse_easyconfigs([(self.eb_file, False)])
752+
self.assertEqual(len(ecs), 1)
753+
self.assertEqual(ecs[0]['spec'], self.eb_file)
754+
self.assertIsInstance(ecs[0]['ec'], EasyConfig)
755+
self.assertFalse(gen_ecs)
756+
# Passing the same EC multiple times is ignored
757+
ecs, gen_ecs = parse_easyconfigs([(self.eb_file, False), (self.eb_file, False)])
758+
self.assertEqual(len(ecs), 1)
759+
# Similar for symlinks
760+
linked_ec = os.path.join(self.test_prefix, 'linked.eb')
761+
os.symlink(self.eb_file, linked_ec)
762+
ecs, gen_ecs = parse_easyconfigs([(self.eb_file, False), (linked_ec, False)])
763+
self.assertEqual(len(ecs), 1)
764+
self.assertEqual(ecs[0]['spec'], self.eb_file)
765+
740766
def test_alt_easyconfig_paths(self):
741767
"""Test alt_easyconfig_paths function that collects list of additional paths for easyconfig files."""
742768

0 commit comments

Comments
 (0)