Skip to content

Commit 91dab1f

Browse files
author
Alan O'Cais
committed
Only copy extension easyblocks *after* we have run the easyblock steps
The reproduction directory is created before we run the steps, when the list of extension easyblock instances is not actually populated yet
1 parent 9d4687a commit 91dab1f

File tree

2 files changed

+65
-17
lines changed

2 files changed

+65
-17
lines changed

easybuild/framework/easyblock.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,7 +3282,14 @@ def build_and_install_one(ecdict, init_env):
32823282
# create our reproducability files before carrying out the easyblock steps
32833283
reprod_dir_root = os.path.dirname(app.logfile)
32843284
reprod_dir = reproduce_build(app, reprod_dir_root)
3285+
32853286
result = app.run_all_steps(run_test_cases=run_test_cases)
3287+
3288+
if not dry_run:
3289+
# also add any extension easyblocks used during the build for reproducability
3290+
if app.ext_instances:
3291+
copy_easyblocks_for_reprod(app.ext_instances, reprod_dir)
3292+
32863293
except EasyBuildError as err:
32873294
first_n = 300
32883295
errormsg = "build failed (first %d chars): %s" % (first_n, err.msg[:first_n])
@@ -3416,6 +3423,25 @@ def build_and_install_one(ecdict, init_env):
34163423
return (success, application_log, errormsg)
34173424

34183425

3426+
def copy_easyblocks_for_reprod(easyblock_instances, reprod_dir):
3427+
reprod_easyblock_dir = os.path.join(reprod_dir, 'easyblocks')
3428+
easyblock_paths = set()
3429+
for easyblock_instance in easyblock_instances:
3430+
for easyblock_class in inspect.getmro(type(easyblock_instance)):
3431+
easyblock_path = inspect.getsourcefile(easyblock_class)
3432+
# if we reach EasyBlock or ExtensionEasyBlock class, we are done
3433+
# (ExtensionEasyblock is hardcoded to avoid a cyclical import)
3434+
if easyblock_class.__name__ in [EasyBlock.__name__, 'ExtensionEasyBlock']:
3435+
break
3436+
else:
3437+
easyblock_paths.add(easyblock_path)
3438+
3439+
for easyblock_path in easyblock_paths:
3440+
easyblock_basedir, easyblock_filename = os.path.split(easyblock_path)
3441+
copy_file(easyblock_path, os.path.join(reprod_easyblock_dir, easyblock_filename))
3442+
_log.info("Dumped easyblock %s required for reproduction to %s", easyblock_filename, reprod_easyblock_dir)
3443+
3444+
34193445
def reproduce_build(app, reprod_dir_root):
34203446
"""
34213447
Create reproducability files (processed easyconfig and easyblocks used) from class instance
@@ -3438,23 +3464,7 @@ def reproduce_build(app, reprod_dir_root):
34383464
_log.warning("Unable to dump easyconfig instance to %s: %s", reprod_spec, err)
34393465

34403466
# also archive all the relevant easyblocks (including any used by extensions)
3441-
reprod_easyblock_dir = os.path.join(reprod_dir, 'easyblocks')
3442-
easyblock_instances = [app] + app.ext_instances
3443-
easyblock_paths = set()
3444-
for easyblock_instance in easyblock_instances:
3445-
for easyblock_class in inspect.getmro(type(easyblock_instance)):
3446-
easyblock_path = inspect.getsourcefile(easyblock_class)
3447-
# if we reach EasyBlock or ExtensionEasyBlock class, we are done
3448-
# (ExtensionEasyblock is hardcoded to avoid a cyclical import)
3449-
if easyblock_class.__name__ in [EasyBlock.__name__, 'ExtensionEasyBlock']:
3450-
break
3451-
else:
3452-
easyblock_paths.add(easyblock_path)
3453-
3454-
for easyblock_path in easyblock_paths:
3455-
easyblock_basedir, easyblock_filename = os.path.split(easyblock_path)
3456-
copy_file(easyblock_path, os.path.join(reprod_easyblock_dir, easyblock_filename))
3457-
_log.info("Dumped easyblock %s required for reproduction to %s", easyblock_filename, reprod_easyblock_dir)
3467+
copy_easyblocks_for_reprod([app], reprod_dir)
34583468

34593469
# if there is a hook file we should also archive it
34603470
hooks_path = build_option('hooks')

test/framework/toy_build.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,6 +1839,44 @@ def test_reproducability(self):
18391839
reprod_hooks = os.path.join(reprod_dir, 'hooks', hooks_filename)
18401840
self.assertTrue(os.path.exists(reprod_hooks))
18411841

1842+
def test_reproducability_ext_easyblocks(self):
1843+
"""Test toy build produces expected reproducability files also when extensions are used"""
1844+
1845+
topdir = os.path.dirname(os.path.abspath(__file__))
1846+
toy_ec_file = os.path.join(topdir, 'easyconfigs', 'test_ecs', 't', 'toy', 'toy-0.0.eb')
1847+
toy_ec_txt = read_file(toy_ec_file)
1848+
1849+
ec1 = os.path.join(self.test_prefix, 'toy1.eb')
1850+
ec1_txt = '\n'.join([
1851+
toy_ec_txt,
1852+
"exts_list = [('barbar', '0.0')]",
1853+
"",
1854+
])
1855+
write_file(ec1, ec1_txt)
1856+
1857+
self.test_toy_build(ec_file=ec1, verify=False, extra_args=['--minimal-toolchains', '--easyblock=EB_toytoy'])
1858+
1859+
# Check whether easyconfig is dumped to reprod/ subdir
1860+
reprod_dir = os.path.join(self.test_installpath, 'software', 'toy', '0.0', 'easybuild', 'reprod')
1861+
reprod_ec = os.path.join(reprod_dir, 'toy-0.0.eb')
1862+
1863+
self.assertTrue(os.path.exists(reprod_ec))
1864+
1865+
# Check for child easyblock existence
1866+
child_easyblock = os.path.join(reprod_dir, 'easyblocks', 'toytoy.py')
1867+
self.assertTrue(os.path.exists(child_easyblock))
1868+
# Check for parent easyblock existence
1869+
parent_easyblock = os.path.join(reprod_dir, 'easyblocks', 'toy.py')
1870+
self.assertTrue(os.path.exists(parent_easyblock))
1871+
# Check for extension easyblock existence
1872+
ext_easyblock = os.path.join(reprod_dir, 'easyblocks', 'toy_extension.py')
1873+
self.assertTrue(os.path.exists(ext_easyblock))
1874+
1875+
# Make sure framework easyblock modules are not included
1876+
for framework_easyblock in ['easyblock.py', 'extensioneasyblock.py']:
1877+
path = os.path.join(reprod_dir, 'easyblocks', framework_easyblock)
1878+
self.assertFalse(os.path.exists(path))
1879+
18421880
def test_toy_toy(self):
18431881
"""Test building two easyconfigs in a single go, with one depending on the other."""
18441882
topdir = os.path.dirname(os.path.abspath(__file__))

0 commit comments

Comments
 (0)