Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions easybuild/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,16 @@ def summary(ecs_with_res):
def build_and_install_software(ecs, init_session_state, exit_on_failure=True, testing=False):
"""
Build and install software for all provided parsed easyconfig files.
The build environment is reset to the one passed by init_session_state between builds.
However, the environment is _not_ reset after the last build.
The environment used for building the software matches the one used to enter this function.
The environment is reset upon finishing a build.

:param ecs: easyconfig files to install software with
:param init_session_state: initial session state, to use in test reports
:param exit_on_failure: whether or not to exit on installation failure
:param exit_on_failure: whether to exit on installation failure
"""
# obtain a copy of the starting environment so each build can start afresh
# we shouldn't use the environment from init_session_state, since relevant env vars might have been set since
# e.g. via easyconfig.handle_allowed_system_deps
# Obtain a copy of the environment when starting to build, so each build can start afresh.
# We shouldn't use the environment from init_session_state, since relevant env vars might have been set since
# e.g. via easyconfig.handle_allowed_system_deps.
init_env = copy.deepcopy(os.environ)

start_progress_bar(STATUS_BAR, size=len(ecs))
Expand All @@ -186,6 +186,11 @@ def build_and_install_software(ecs, init_session_state, exit_on_failure=True, te
ec_res['success'] = False
ec_res['err'] = err
ec_res['traceback'] = traceback.format_exc()
finally:
# Do not wait for final build, since we might raise an error on a failed build,
# leaving a tainted environment. With this, we ensure that we always properly clean up.
_log.info("Resetting environment after completed build")
restore_env(init_env)

if ec_res['success']:
ec_results.append(ec['full_mod_name'] + ' (' + colorize('OK', COLOR_GREEN) + ')')
Expand Down
23 changes: 19 additions & 4 deletions test/framework/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@
import easybuild.tools.toolchain as toolchain
import easybuild.tools.toolchain.compiler
from easybuild.framework.easyconfig.easyconfig import EasyConfig, ActiveMNS
from easybuild.framework.easyblock import EasyBlock
from easybuild.toolchains.compiler.gcc import Gcc
from easybuild.toolchains.system import SystemToolchain
from easybuild.tools import LooseVersion
from easybuild.tools import systemtools as st
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.config import update_build_option
from easybuild.tools.environment import setvar
from easybuild.tools.filetools import adjust_permissions, copy_dir, find_eb_script, mkdir
from easybuild.tools.filetools import read_file, symlink, write_file, which
Expand Down Expand Up @@ -2484,8 +2486,12 @@ def test_compiler_cache(self):
ccache_dir = os.path.join(self.test_prefix, 'ccache')
mkdir(ccache_dir, parents=True)

# keep track of old CCACHE_DIR variable, so that we can check if this is properly reset after running 'eb'
old_ccache_dir_env = 'ThisIsATest'
os.environ['CCACHE_DIR'] = old_ccache_dir_env
with self.mocked_stdout_stderr():
out = self.eb_main(args, raise_error=True, do_build=True, reset_env=False)
self.assertEqual(os.environ.get('CCACHE_DIR', ''), old_ccache_dir_env)

patterns = [
"This is a ccache wrapper",
Expand All @@ -2495,7 +2501,14 @@ def test_compiler_cache(self):
regex = re.compile(pattern)
self.assertTrue(regex.search(out), "Pattern '%s' found in: %s" % (regex.pattern, out))

# $CCACHE_DIR is defined by toolchain.prepare(), and should still be defined after running 'eb'
# $CCACHE_DIR is defined by toolchain.prepare()
# All further tests use this environment
with self.mocked_stdout_stderr():
update_build_option('use_ccache', os.path.join(self.test_prefix, 'ccache'))
ec = EasyConfig(eb_file)
eb = EasyBlock(ec)
eb.toolchain.prepare()

ccache_path = os.path.join(self.test_prefix, 'scripts', 'ccache')
self.assertTrue(os.path.samefile(os.environ['CCACHE_DIR'], ccache_dir))
for comp in ['gcc', 'g++']:
Expand All @@ -2514,10 +2527,12 @@ def test_compiler_cache(self):
# if both ccache and f90cache are used, Fortran compiler is symlinked to f90cache
f90cache_dir = os.path.join(self.test_prefix, 'f90cache')
mkdir(f90cache_dir, parents=True)
args.append("--use-f90cache=%s" % f90cache_dir)

with self.mocked_stdout_stderr():
out = self.eb_main(args, raise_error=True, do_build=True, reset_env=False)
update_build_option('use_f90cache', f90cache_dir)
ec = EasyConfig(eb_file)
eb = EasyBlock(ec)
eb.toolchain.prepare()

for pattern in patterns:
regex = re.compile(pattern)
self.assertTrue(regex.search(out), "Pattern '%s' found in: %s" % (regex.pattern, out))
Expand Down