@@ -1504,13 +1504,14 @@ def make_module_req_guess(self):
15041504 'CMAKE_LIBRARY_PATH' : ['lib64' ], # lib and lib32 are searched through the above
15051505 }
15061506
1507- def load_module (self , mod_paths = None , purge = True , extra_modules = None ):
1507+ def load_module (self , mod_paths = None , purge = True , extra_modules = None , verbose = True ):
15081508 """
15091509 Load module for this software package/version, after purging all currently loaded modules.
15101510
15111511 :param mod_paths: list of (additional) module paths to take into account
15121512 :param purge: boolean indicating whether or not to purge currently loaded modules first
15131513 :param extra_modules: list of extra modules to load (these are loaded *before* loading the 'self' module)
1514+ :param verbose: print modules being loaded when trace mode is enabled
15141515 """
15151516 # self.full_mod_name might not be set (e.g. during unit tests)
15161517 if self .full_mod_name is not None :
@@ -1532,6 +1533,9 @@ def load_module(self, mod_paths=None, purge=True, extra_modules=None):
15321533 if self .mod_subdir and not self .toolchain .is_system_toolchain ():
15331534 mods .insert (0 , self .toolchain .det_short_module_name ())
15341535
1536+ if verbose :
1537+ trace_msg ("loading modules: %s..." % ', ' .join (mods ))
1538+
15351539 # pass initial environment, to use it for resetting the environment before loading the modules
15361540 self .modules_tool .load (mods , mod_paths = all_mod_paths , purge = purge , init_env = self .initial_environ )
15371541
@@ -1543,7 +1547,7 @@ def load_module(self, mod_paths=None, purge=True, extra_modules=None):
15431547 else :
15441548 self .log .warning ("Not loading module, since self.full_mod_name is not set." )
15451549
1546- def load_fake_module (self , purge = False , extra_modules = None ):
1550+ def load_fake_module (self , purge = False , extra_modules = None , verbose = False ):
15471551 """
15481552 Create and load fake module.
15491553
@@ -1558,7 +1562,7 @@ def load_fake_module(self, purge=False, extra_modules=None):
15581562
15591563 # load fake module
15601564 self .modules_tool .prepend_module_path (os .path .join (fake_mod_path , self .mod_subdir ), priority = 10000 )
1561- self .load_module (purge = purge , extra_modules = extra_modules )
1565+ self .load_module (purge = purge , extra_modules = extra_modules , verbose = verbose )
15621566
15631567 return (fake_mod_path , env )
15641568
@@ -2235,54 +2239,32 @@ def install_step(self):
22352239 """Install built software (abstract method)."""
22362240 raise NotImplementedError
22372241
2238- def extensions_step (self , fetch = False , install = True ):
2242+ def init_ext_instances (self ):
22392243 """
2240- After make install, run this.
2241- - only if variable len(exts_list) > 0
2242- - optionally: load module that was just created using temp module file
2243- - find source for extensions, in 'extensions' (and 'packages' for legacy reasons)
2244- - run extra_extensions
2244+ Create class instances for all extensions.
22452245 """
2246- if not self .cfg .get_ref ('exts_list' ):
2247- self .log .debug ("No extensions in exts_list" )
2248- return
2249-
2250- # load fake module
2251- fake_mod_data = None
2252- if install and not self .dry_run :
2253-
2254- # load modules for build dependencies as extra modules
2255- build_dep_mods = [dep ['short_mod_name' ] for dep in self .cfg .dependencies (build_only = True )]
2256-
2257- fake_mod_data = self .load_fake_module (purge = True , extra_modules = build_dep_mods )
2258-
2259- self .prepare_for_extensions ()
2260-
2261- if fetch :
2262- self .exts = self .fetch_extension_sources ()
2246+ exts_list = self .cfg .get_ref ('exts_list' )
22632247
2264- self .exts_all = self .exts [:] # retain a copy of all extensions, regardless of filtering/skipping
2248+ # early exit if there are no extensions
2249+ if not exts_list :
2250+ return
22652251
2266- # actually install extensions
2267- self .log .debug ("Installing extensions" )
2268- exts_defaultclass = self .cfg ['exts_defaultclass' ]
2252+ self .ext_instances = []
22692253 exts_classmap = self .cfg ['exts_classmap' ]
22702254
2271- # we really need a default class
2272- if not exts_defaultclass and fake_mod_data :
2273- self .clean_up_fake_module (fake_mod_data )
2274- raise EasyBuildError ("ERROR: No default extension class set for %s" , self .name )
2255+ if exts_list and not self .exts :
2256+ self .exts = self .fetch_extension_sources ()
22752257
22762258 # obtain name and module path for default extention class
2259+ exts_defaultclass = self .cfg ['exts_defaultclass' ]
22772260 if isinstance (exts_defaultclass , string_type ):
22782261 # proper way: derive module path from specified class name
22792262 default_class = exts_defaultclass
22802263 default_class_modpath = get_module_path (default_class , generic = True )
22812264 else :
2282- raise EasyBuildError ("Improper default extension class specification, should be string." )
2265+ error_msg = "Improper default extension class specification, should be string: %s (%s)"
2266+ raise EasyBuildError (error_msg , exts_defaultclass , type (exts_defaultclass ))
22832267
2284- # get class instances for all extensions
2285- self .ext_instances = []
22862268 for ext in self .exts :
22872269 ext_name = ext ['name' ]
22882270 self .log .debug ("Creating class instance for extension %s..." , ext_name )
@@ -2332,6 +2314,45 @@ def extensions_step(self, fetch=False, install=True):
23322314
23332315 self .ext_instances .append (inst )
23342316
2317+ def extensions_step (self , fetch = False , install = True ):
2318+ """
2319+ After make install, run this.
2320+ - only if variable len(exts_list) > 0
2321+ - optionally: load module that was just created using temp module file
2322+ - find source for extensions, in 'extensions' (and 'packages' for legacy reasons)
2323+ - run extra_extensions
2324+ """
2325+ if not self .cfg .get_ref ('exts_list' ):
2326+ self .log .debug ("No extensions in exts_list" )
2327+ return
2328+
2329+ # load fake module
2330+ fake_mod_data = None
2331+ if install and not self .dry_run :
2332+
2333+ # load modules for build dependencies as extra modules
2334+ build_dep_mods = [dep ['short_mod_name' ] for dep in self .cfg .dependencies (build_only = True )]
2335+
2336+ fake_mod_data = self .load_fake_module (purge = True , extra_modules = build_dep_mods )
2337+
2338+ self .prepare_for_extensions ()
2339+
2340+ if fetch :
2341+ self .exts = self .fetch_extension_sources ()
2342+
2343+ self .exts_all = self .exts [:] # retain a copy of all extensions, regardless of filtering/skipping
2344+
2345+ # actually install extensions
2346+ if install :
2347+ self .log .info ("Installing extensions" )
2348+
2349+ # we really need a default class
2350+ if not self .cfg ['exts_defaultclass' ] and fake_mod_data :
2351+ self .clean_up_fake_module (fake_mod_data )
2352+ raise EasyBuildError ("ERROR: No default extension class set for %s" , self .name )
2353+
2354+ self .init_ext_instances ()
2355+
23352356 if self .skip :
23362357 self .skip_extensions ()
23372358
@@ -2347,7 +2368,7 @@ def extensions_step(self, fetch=False, install=True):
23472368 print_msg ("installing extension %s %s (%d/%d)..." % tup , silent = self .silent )
23482369
23492370 if self .dry_run :
2350- tup = (ext .name , ext .version , cls .__name__ )
2371+ tup = (ext .name , ext .version , ext . __class__ .__name__ )
23512372 msg = "\n * installing extension %s %s using '%s' easyblock\n " % tup
23522373 self .dry_run_msg (msg )
23532374
@@ -2890,6 +2911,13 @@ def _sanity_check_step_dry_run(self, custom_paths=None, custom_commands=None, **
28902911 def _sanity_check_step_extensions (self ):
28912912 """Sanity check on extensions (if any)."""
28922913 failed_exts = []
2914+
2915+ # class instances for extensions may not be initialized yet here,
2916+ # for example when using --module-only or --sanity-check-only
2917+ if not self .ext_instances :
2918+ self .prepare_for_extensions ()
2919+ self .init_ext_instances ()
2920+
28932921 for ext in self .ext_instances :
28942922 success , fail_msg = None , None
28952923 res = ext .sanity_check_step ()
@@ -2981,12 +3009,16 @@ def xs2str(xs):
29813009
29823010 fake_mod_data = None
29833011
3012+ # skip loading of fake module when using --sanity-check-only, load real module instead
3013+ if build_option ('sanity_check_only' ) and not extension :
3014+ self .load_module (extra_modules = extra_modules )
3015+
29843016 # only load fake module for non-extensions, and not during dry run
2985- if not (extension or self .dry_run ):
3017+ elif not (extension or self .dry_run ):
29863018 try :
29873019 # unload all loaded modules before loading fake module
29883020 # this ensures that loading of dependencies is tested, and avoids conflicts with build dependencies
2989- fake_mod_data = self .load_fake_module (purge = True , extra_modules = extra_modules )
3021+ fake_mod_data = self .load_fake_module (purge = True , extra_modules = extra_modules , verbose = True )
29903022 except EasyBuildError as err :
29913023 self .sanity_check_fail_msgs .append ("loading fake module failed: %s" % err )
29923024 self .log .warning ("Sanity check: %s" % self .sanity_check_fail_msgs [- 1 ])
@@ -3270,16 +3302,18 @@ def update_config_template_run_step(self):
32703302
32713303 def skip_step (self , step , skippable ):
32723304 """Dedice whether or not to skip the specified step."""
3273- module_only = build_option ('module_only' )
3274- force = build_option ('force' )
32753305 skip = False
3306+ force = build_option ('force' )
3307+ module_only = build_option ('module_only' )
3308+ sanity_check_only = build_option ('sanity_check_only' )
3309+ skipsteps = self .cfg ['skipsteps' ]
32763310
32773311 # under --skip, sanity check is not skipped
32783312 cli_skip = self .skip and step != SANITYCHECK_STEP
32793313
32803314 # skip step if specified as individual (skippable) step, or if --skip is used
3281- if skippable and (cli_skip or step in self . cfg [ ' skipsteps' ] ):
3282- self .log .info ("Skipping %s step (skip: %s, skipsteps: %s)" , step , self .skip , self . cfg [ ' skipsteps' ] )
3315+ if skippable and (cli_skip or step in skipsteps ):
3316+ self .log .info ("Skipping %s step (skip: %s, skipsteps: %s)" , step , self .skip , skipsteps )
32833317 skip = True
32843318
32853319 # skip step when only generating module file
@@ -3294,9 +3328,14 @@ def skip_step(self, step, skippable):
32943328 self .log .info ("Skipping %s step because of forced module-only mode" , step )
32953329 skip = True
32963330
3331+ elif sanity_check_only and step != SANITYCHECK_STEP :
3332+ self .log .info ("Skipping %s step because of sanity-check-only mode" , step )
3333+ skip = True
3334+
32973335 else :
3298- self .log .debug ("Not skipping %s step (skippable: %s, skip: %s, skipsteps: %s, module_only: %s, force: %s" ,
3299- step , skippable , self .skip , self .cfg ['skipsteps' ], module_only , force )
3336+ msg = "Not skipping %s step (skippable: %s, skip: %s, skipsteps: %s, module_only: %s, force: %s, "
3337+ msg += "sanity_check_only: %s)"
3338+ self .log .debug (msg , step , skippable , self .skip , skipsteps , module_only , force , sanity_check_only )
33003339
33013340 return skip
33023341
0 commit comments