5656import time
5757import traceback
5858from concurrent .futures import ThreadPoolExecutor
59+ from contextlib import contextmanager
5960from datetime import datetime
6061from string import ascii_letters
6162from textwrap import indent
@@ -1268,9 +1269,6 @@ def make_devel_module(self, create_in_builddir=False):
12681269
12691270 self .log .info ("Making devel module..." )
12701271
1271- # load fake module
1272- fake_mod_data = self .load_fake_module (purge = True )
1273-
12741272 header = self .module_generator .MODULE_SHEBANG
12751273 if header :
12761274 header += '\n '
@@ -1314,9 +1312,6 @@ def make_devel_module(self, create_in_builddir=False):
13141312 txt = '' .join ([header ] + load_lines + env_lines )
13151313 write_file (filename , txt )
13161314
1317- # cleanup: unload fake module, remove fake module dir
1318- self .clean_up_fake_module (fake_mod_data )
1319-
13201315 def make_module_deppaths (self ):
13211316 """
13221317 Add specific 'module use' actions to module file, in order to find
@@ -1646,7 +1641,7 @@ def make_module_group_check(self):
16461641
16471642 return txt
16481643
1649- def make_module_req (self , fake = False ):
1644+ def make_module_req (self ):
16501645 """
16511646 Generate the environment-variables required to run the module.
16521647 """
@@ -1687,11 +1682,10 @@ def make_module_req(self, fake=False):
16871682 mod_lines .append (self .module_generator .comment (note ))
16881683
16891684 for env_var , search_paths in env_var_requirements .items ():
1690- if self .dry_run or fake :
1685+ if self .dry_run :
16911686 # Don't expand globs or do any filtering for dry run
16921687 mod_req_paths = search_paths
1693- if self .dry_run :
1694- self .dry_run_msg (f" ${ env_var } :{ ', ' .join (mod_req_paths )} " )
1688+ self .dry_run_msg (f" ${ env_var } :{ ', ' .join (mod_req_paths )} " )
16951689 else :
16961690 mod_req_paths = [
16971691 expanded_path for unexpanded_path in search_paths
@@ -1888,7 +1882,6 @@ def load_fake_module(self, purge=False, extra_modules=None, verbose=False):
18881882 # load fake module
18891883 self .modules_tool .prepend_module_path (os .path .join (fake_mod_path , self .mod_subdir ), priority = 10000 )
18901884 self .load_module (purge = purge , extra_modules = extra_modules , verbose = verbose )
1891-
18921885 return (fake_mod_path , env )
18931886
18941887 def clean_up_fake_module (self , fake_mod_data ):
@@ -1972,10 +1965,11 @@ def skip_extensions(self):
19721965 if not exts_filter or len (exts_filter ) == 0 :
19731966 raise EasyBuildError ("Skipping of extensions, but no exts_filter set in easyconfig" )
19741967
1975- if build_option ('parallel_extensions_install' ):
1976- self .skip_extensions_parallel (exts_filter )
1977- else :
1978- self .skip_extensions_sequential (exts_filter )
1968+ with self .fake_module_environment ():
1969+ if build_option ('parallel_extensions_install' ):
1970+ self .skip_extensions_parallel (exts_filter )
1971+ else :
1972+ self .skip_extensions_sequential (exts_filter )
19791973
19801974 def skip_extensions_sequential (self , exts_filter ):
19811975 """
@@ -2103,31 +2097,27 @@ def install_extensions_sequential(self, install=True):
21032097 msg = "\n * installing extension %s %s using '%s' easyblock\n " % tup
21042098 self .dry_run_msg (msg )
21052099
2106- self .log .debug ("List of loaded modules: %s" , self .modules_tool .list ())
2107-
2108- # prepare toolchain build environment, but only when not doing a dry run
2109- # since in that case the build environment is the same as for the parent
21102100 if self .dry_run :
21112101 self .dry_run_msg ("defining build environment based on toolchain (options) and dependencies..." )
2112- else :
2113- # don't reload modules for toolchain, there is no need since they will be loaded already;
2114- # the (fake) module for the parent software gets loaded before installing extensions
2115- ext .toolchain .prepare (onlymod = self .cfg ['onlytcmod' ], silent = True , loadmod = False ,
2116- rpath_filter_dirs = self .rpath_filter_dirs ,
2117- rpath_include_dirs = self .rpath_include_dirs ,
2118- rpath_wrappers_dir = self .rpath_wrappers_dir )
21192102
21202103 # actual installation of the extension
2121- if install :
2122- try :
2123- ext .install_extension_substep ("pre_install_extension" )
2124- with self .module_generator .start_module_creation ():
2125- txt = ext .install_extension_substep ("install_extension" )
2126- if txt :
2127- self .module_extra_extensions += txt
2128- ext .install_extension_substep ("post_install_extension" )
2129- finally :
2130- if not self .dry_run :
2104+ if install and not self .dry_run :
2105+ with self .fake_module_environment (with_build_deps = True ):
2106+ self .log .debug ("List of loaded modules: %s" , self .modules_tool .list ())
2107+ # don't reload modules for toolchain, there is no need
2108+ # since they will be loaded already by the fake module
2109+ ext .toolchain .prepare (onlymod = self .cfg ['onlytcmod' ], silent = True , loadmod = False ,
2110+ rpath_filter_dirs = self .rpath_filter_dirs ,
2111+ rpath_include_dirs = self .rpath_include_dirs ,
2112+ rpath_wrappers_dir = self .rpath_wrappers_dir )
2113+ try :
2114+ ext .install_extension_substep ("pre_install_extension" )
2115+ with self .module_generator .start_module_creation ():
2116+ txt = ext .install_extension_substep ("install_extension" )
2117+ if txt :
2118+ self .module_extra_extensions += txt
2119+ ext .install_extension_substep ("post_install_extension" )
2120+ finally :
21312121 ext_duration = datetime .now () - start_time
21322122 if ext_duration .total_seconds () >= 1 :
21332123 print_msg ("\t ... (took %s)" , time2str (ext_duration ), log = self .log , silent = self .silent )
@@ -2274,17 +2264,18 @@ def update_exts_progress_bar_helper(running_exts, progress_size):
22742264 tup = (ext .name , ext .version or '' )
22752265 print_msg ("starting installation of extension %s %s..." % tup , silent = self .silent , log = self .log )
22762266
2277- # don't reload modules for toolchain, there is no need since they will be loaded already;
2278- # the (fake) module for the parent software gets loaded before installing extensions
2279- ext .toolchain .prepare (onlymod = self .cfg ['onlytcmod' ], silent = True , loadmod = False ,
2280- rpath_filter_dirs = self .rpath_filter_dirs ,
2281- rpath_include_dirs = self .rpath_include_dirs ,
2282- rpath_wrappers_dir = self .rpath_wrappers_dir )
2283- if install :
2284- ext .install_extension_substep ("pre_install_extension" )
2285- ext .async_cmd_task = ext .install_extension_substep ("install_extension_async" , thread_pool )
2286- running_exts .append (ext )
2287- self .log .info (f"Started installation of extension { ext .name } in the background..." )
2267+ if install and not self .dry_run :
2268+ with self .fake_module_environment (with_build_deps = True ):
2269+ # don't reload modules for toolchain, there is no
2270+ # need since they will be loaded by the fake module
2271+ ext .toolchain .prepare (onlymod = self .cfg ['onlytcmod' ], silent = True , loadmod = False ,
2272+ rpath_filter_dirs = self .rpath_filter_dirs ,
2273+ rpath_include_dirs = self .rpath_include_dirs ,
2274+ rpath_wrappers_dir = self .rpath_wrappers_dir )
2275+ ext .install_extension_substep ("pre_install_extension" )
2276+ ext .async_cmd_task = ext .install_extension_substep ("install_extension_async" , thread_pool )
2277+ running_exts .append (ext )
2278+ self .log .info (f"Started installation of extension { ext .name } in the background..." )
22882279 update_exts_progress_bar_helper (running_exts , 0 )
22892280
22902281 # print progress info after every iteration (unless that info is already shown via progress bar)
@@ -2308,6 +2299,25 @@ def start_dir(self):
23082299 """Start directory in build directory"""
23092300 return self .cfg ['start_dir' ]
23102301
2302+ @contextmanager
2303+ def fake_module_environment (self , extra_modules = None , with_build_deps = False ):
2304+ """
2305+ Load/Unload fake module
2306+ """
2307+ fake_mod_data = None
2308+
2309+ if with_build_deps :
2310+ # load modules for build dependencies as extra modules
2311+ extra_modules = [dep ['short_mod_name' ] for dep in self .cfg .dependencies (build_only = True )]
2312+
2313+ fake_mod_data = self .load_fake_module (purge = True , extra_modules = extra_modules )
2314+
2315+ yield
2316+
2317+ # cleanup (unload fake module, remove fake module dir)
2318+ if fake_mod_data :
2319+ self .clean_up_fake_module (fake_mod_data )
2320+
23112321 def guess_start_dir (self ):
23122322 """
23132323 Return the directory where to start the whole configure/make/make install cycle from
@@ -3130,14 +3140,9 @@ def extensions_step(self, fetch=False, install=True):
31303140 self .log .debug ("No extensions in exts_list" )
31313141 return
31323142
3133- # load fake module
3134- fake_mod_data = None
3135- if install and not self .dry_run :
3136-
3137- # load modules for build dependencies as extra modules
3138- build_dep_mods = [dep ['short_mod_name' ] for dep in self .cfg .dependencies (build_only = True )]
3139-
3140- fake_mod_data = self .load_fake_module (purge = True , extra_modules = build_dep_mods )
3143+ # we really need a default class
3144+ if not self .cfg ['exts_defaultclass' ] and install :
3145+ raise EasyBuildError ("ERROR: No default extension class set for %s" , self .name )
31413146
31423147 start_progress_bar (PROGRESS_BAR_EXTENSIONS , len (self .cfg .get_ref ('exts_list' )))
31433148
@@ -3153,22 +3158,13 @@ def extensions_step(self, fetch=False, install=True):
31533158 if install :
31543159 self .log .info ("Installing extensions" )
31553160
3156- # we really need a default class
3157- if not self .cfg ['exts_defaultclass' ] and fake_mod_data :
3158- self .clean_up_fake_module (fake_mod_data )
3159- raise EasyBuildError ("ERROR: No default extension class set for %s" , self .name )
3160-
31613161 self .init_ext_instances ()
31623162
31633163 if self .skip :
31643164 self .skip_extensions ()
31653165
31663166 self .install_all_extensions (install = install )
31673167
3168- # cleanup (unload fake module, remove fake module dir)
3169- if fake_mod_data :
3170- self .clean_up_fake_module (fake_mod_data )
3171-
31723168 stop_progress_bar (PROGRESS_BAR_EXTENSIONS , visible = False )
31733169
31743170 def package_step (self ):
@@ -4078,7 +4074,7 @@ def make_module_step(self, fake=False):
40784074 txt += self .make_module_deppaths ()
40794075 txt += self .make_module_dep ()
40804076 txt += self .make_module_extend_modpath ()
4081- txt += self .make_module_req (fake = fake )
4077+ txt += self .make_module_req ()
40824078 txt += self .make_module_extra ()
40834079 txt += self .make_module_footer ()
40844080
@@ -4122,13 +4118,14 @@ def make_module_step(self, fake=False):
41224118 self .module_generator .create_symlinks (mod_symlink_paths , fake = fake )
41234119
41244120 if ActiveMNS ().mns .det_make_devel_module () and not fake and build_option ('generate_devel_module' ):
4125- try :
4126- self .make_devel_module ()
4127- except EasyBuildError as error :
4128- if build_option ('module_only' ) or self .cfg ['module_only' ]:
4129- self .log .info ("Using --module-only so can recover from error: %s" , error )
4130- else :
4131- raise error
4121+ with self .fake_module_environment ():
4122+ try :
4123+ self .make_devel_module ()
4124+ except EasyBuildError as error :
4125+ if build_option ('module_only' ) or self .cfg ['module_only' ]:
4126+ self .log .info ("Using --module-only so can recover from error: %s" , error )
4127+ else :
4128+ raise error
41324129 else :
41334130 self .log .info ("Skipping devel module..." )
41344131
0 commit comments