6565from easybuild .tools .config import install_path , log_path , package_path , source_paths
6666from easybuild .tools .environment import restore_env , sanitize_env
6767from easybuild .tools .filetools import DEFAULT_CHECKSUM
68- from easybuild .tools .filetools import adjust_permissions , apply_patch , convert_name , derive_alt_pypi_url
68+ from easybuild .tools .filetools import adjust_permissions , apply_patch , change_dir , convert_name , derive_alt_pypi_url
6969from easybuild .tools .filetools import compute_checksum , download_file , encode_class_name , extract_file
7070from easybuild .tools .filetools import is_alt_pypi_url , mkdir , move_logs , read_file , remove_file , rmtree2 , write_file
7171from easybuild .tools .filetools import verify_checksum , weld_paths
@@ -912,21 +912,23 @@ def make_module_dep(self, unload_info=None):
912912
913913 :param unload_info: dictionary with full module names as keys and module name to unload first as corr. value
914914 """
915- deps = []
916915 mns = ActiveMNS ()
917916 unload_info = unload_info or {}
918917
919- # include load statements for toolchain, either directly or for toolchain dependencies
918+ # include toolchain as first dependency to load
919+ tc_mod = None
920920 if self .toolchain .name != DUMMY_TOOLCHAIN_NAME :
921- if mns .expand_toolchain_load ():
922- mod_names = self .toolchain .toolchain_dep_mods
923- deps .extend (mod_names )
924- self .log .debug ("Adding toolchain components as module dependencies: %s" % mod_names )
925- else :
926- deps .append (self .toolchain .det_short_module_name ())
927- self .log .debug ("Adding toolchain %s as a module dependency" % deps [- 1 ])
921+ tc_mod = self .toolchain .det_short_module_name ()
922+ self .log .debug ("Toolchain to load in generated module (before excluding any deps): %s" , tc_mod )
923+
924+ # expand toolchain into toolchain components if desired
925+ tc_dep_mods = None
926+ if mns .expand_toolchain_load (ec = self .cfg ):
927+ tc_dep_mods = self .toolchain .toolchain_dep_mods
928+ self .log .debug ("Toolchain components to load in generated module (before excluding any): %s" , tc_dep_mods )
928929
929930 # include load/unload statements for dependencies
931+ deps = []
930932 self .log .debug ("List of deps considered to load in generated module: %s" , self .toolchain .dependencies )
931933 for dep in self .toolchain .dependencies :
932934 if dep ['build_only' ]:
@@ -935,35 +937,52 @@ def make_module_dep(self, unload_info=None):
935937 modname = dep ['short_mod_name' ]
936938 self .log .debug ("Adding %s as a module dependency" % modname )
937939 deps .append (modname )
938-
939940 self .log .debug ("List of deps to load in generated module (before excluding any): %s" , deps )
940941
941942 # exclude dependencies that extend $MODULEPATH and form the path to the top of the module tree (if any)
942943 full_mod_subdir = os .path .join (self .installdir_mod , self .mod_subdir )
943944 init_modpaths = mns .det_init_modulepaths (self .cfg )
944945 top_paths = [self .installdir_mod ] + [os .path .join (self .installdir_mod , p ) for p in init_modpaths ]
946+
947+ all_deps = [d for d in [tc_mod ] + (tc_dep_mods or []) + deps if d is not None ]
945948 excluded_deps = self .modules_tool .path_to_top_of_module_tree (top_paths , self .cfg .short_mod_name ,
946- full_mod_subdir , deps )
949+ full_mod_subdir , all_deps )
950+
951+ # if the toolchain is excluded, so should the toolchain components
952+ if tc_mod in excluded_deps and tc_dep_mods :
953+ excluded_deps .extend (tc_dep_mods )
954+
947955 self .log .debug ("List of excluded deps: %s" , excluded_deps )
948956
949- # load modules that open up the module tree before checking deps of deps (in reverse order)
950- self .modules_tool .load (excluded_deps [::- 1 ])
957+ # expand toolchain into toolchain components if desired
958+ if tc_dep_mods is not None :
959+ deps = tc_dep_mods + deps
960+ elif tc_mod is not None :
961+ deps = [tc_mod ] + deps
951962
963+ # filter dependencies to avoid including loads for toolchain or toolchain components that extend $MODULEPATH
964+ # with location to where this module is being installed (full_mod_subdir);
965+ # if the modules that extend $MODULEPATH are not loaded this module is not available, so there is not
966+ # point in loading them again (in fact, it may cause problems when reloading this module due to a load storm)
952967 deps = [d for d in deps if d not in excluded_deps ]
953- for dep in excluded_deps :
954- excluded_dep_deps = dependencies_for (dep , self .modules_tool )
955- self .log .debug ("List of dependencies for excluded dependency %s: %s" % (dep , excluded_dep_deps ))
968+
969+ # load modules that open up the module tree before checking deps of deps (in reverse order)
970+ self .modules_tool .load (excluded_deps [::- 1 ])
971+
972+ for excluded_dep in excluded_deps :
973+ excluded_dep_deps = dependencies_for (excluded_dep , self .modules_tool )
974+ self .log .debug ("List of dependencies for excluded dependency %s: %s" % (excluded_dep , excluded_dep_deps ))
956975 deps = [d for d in deps if d not in excluded_dep_deps ]
957976
958- self .log .debug ("List of retained deps to load in generated module: %s" % deps )
959- recursive_unload = self .cfg ['recursive_module_unload' ]
977+ self .log .debug ("List of retained deps to load in generated module: %s" , deps )
960978
979+ # include load statements for retained dependencies
961980 loads = []
962981 for dep in deps :
963982 unload_modules = []
964983 if dep in unload_info :
965984 unload_modules .append (unload_info [dep ])
966- loads .append (self .module_generator .load_module (dep , recursive_unload = recursive_unload ,
985+ loads .append (self .module_generator .load_module (dep , recursive_unload = self . cfg [ 'recursive_module_unload' ] ,
967986 unload_modules = unload_modules ))
968987
969988 # Force unloading any other modules
@@ -1111,10 +1130,7 @@ def make_module_req(self):
11111130
11121131 lines = []
11131132 if os .path .isdir (self .installdir ):
1114- try :
1115- os .chdir (self .installdir )
1116- except OSError , err :
1117- raise EasyBuildError ("Failed to change to %s: %s" , self .installdir , err )
1133+ change_dir (self .installdir )
11181134
11191135 lines .append ('\n ' )
11201136
@@ -1143,10 +1159,7 @@ def make_module_req(self):
11431159 lines .append (self .module_generator .prepend_paths (key , paths ))
11441160 if self .dry_run :
11451161 self .dry_run_msg ('' )
1146- try :
1147- os .chdir (self .orig_workdir )
1148- except OSError , err :
1149- raise EasyBuildError ("Failed to change back to %s: %s" , self .orig_workdir , err )
1162+ change_dir (self .orig_workdir )
11501163
11511164 return '' .join (lines )
11521165
@@ -1332,11 +1345,8 @@ def guess_start_dir(self):
13321345
13331346 self .log .info ("Using %s as start dir" , self .cfg ['start_dir' ])
13341347
1335- try :
1336- os .chdir (self .cfg ['start_dir' ])
1337- self .log .debug ("Changed to real build directory %s (start_dir)" % self .cfg ['start_dir' ])
1338- except OSError , err :
1339- raise EasyBuildError ("Can't change to real build directory %s: %s" , self .cfg ['start_dir' ], err )
1348+ change_dir (self .cfg ['start_dir' ])
1349+ self .log .debug ("Changed to real build directory %s (start_dir)" , self .cfg ['start_dir' ])
13401350
13411351 def handle_iterate_opts (self ):
13421352 """Handle options relevant during iterated part of build/install procedure."""
@@ -1509,13 +1519,13 @@ def fetch_step(self, skip_checksums=False):
15091519 # create parent dirs in install and modules path already
15101520 # this is required when building in parallel
15111521 mod_symlink_paths = ActiveMNS ().det_module_symlink_paths (self .cfg )
1512- parent_subdir = os .path .dirname (self .install_subdir )
1522+ mod_subdir = os .path .dirname (ActiveMNS (). det_full_module_name ( self .cfg ) )
15131523 pardirs = [
15141524 self .installdir ,
1515- os .path .join (self .installdir_mod , parent_subdir ),
1525+ os .path .join (self .installdir_mod , mod_subdir ),
15161526 ]
15171527 for mod_symlink_path in mod_symlink_paths :
1518- pardirs .append (os .path .join (install_path ('mod' ), mod_symlink_path , parent_subdir ))
1528+ pardirs .append (os .path .join (install_path ('mod' ), mod_symlink_path , mod_subdir ))
15191529
15201530 self .log .info ("Checking dirs that need to be created: %s" % pardirs )
15211531 for pardir in pardirs :
@@ -1707,7 +1717,7 @@ def extensions_step(self, fetch=False):
17071717 print_msg ("installing extension %s %s (%d/%d)..." % tup , silent = self .silent )
17081718
17091719 # always go back to original work dir to avoid running stuff from a dir that no longer exists
1710- os . chdir (self .orig_workdir )
1720+ change_dir (self .orig_workdir )
17111721
17121722 cls , inst = None , None
17131723 class_name = encode_class_name (ext ['name' ])
@@ -1717,7 +1727,8 @@ def extensions_step(self, fetch=False):
17171727 try :
17181728 # no error when importing class fails, in case we run into an existing easyblock
17191729 # with a similar name (e.g., Perl Extension 'GO' vs 'Go' for which 'EB_Go' is available)
1720- cls = get_easyblock_class (None , name = ext ['name' ], default_fallback = False , error_on_failed_import = False )
1730+ cls = get_easyblock_class (None , name = ext ['name' ], error_on_failed_import = False ,
1731+ error_on_missing_easyblock = False )
17211732 self .log .debug ("Obtained class %s for extension %s" % (cls , ext ['name' ]))
17221733 if cls is not None :
17231734 inst = cls (self , ext )
@@ -2033,10 +2044,7 @@ def _sanity_check_step(self, custom_paths=None, custom_commands=None, extension=
20332044
20342045 # chdir to installdir (better environment for running tests)
20352046 if os .path .isdir (self .installdir ):
2036- try :
2037- os .chdir (self .installdir )
2038- except OSError , err :
2039- raise EasyBuildError ("Failed to move to installdir %s: %s" , self .installdir , err )
2047+ change_dir (self .installdir )
20402048
20412049 # run sanity check commands
20422050 for command in commands :
@@ -2074,6 +2082,18 @@ def _sanity_check_step(self, custom_paths=None, custom_commands=None, extension=
20742082 else :
20752083 self .log .debug ("Sanity check passed!" )
20762084
2085+ def _set_module_as_default (self ):
2086+ """
2087+ Defining default module Version
2088+
2089+ sets the default module version except if we are in dry run.
2090+ """
2091+ if self .dry_run :
2092+ dry_run_msg ("Marked %s v%s as default version" % (self .name , self .version ))
2093+ else :
2094+ mod_folderpath = os .path .dirname (self .module_generator .get_module_filepath ())
2095+ self .module_generator .set_as_default (mod_folderpath , self .version )
2096+
20772097 def cleanup_step (self ):
20782098 """
20792099 Cleanup leftover mess: remove/clean build directory
@@ -2082,11 +2102,12 @@ def cleanup_step(self):
20822102 cleanup_builddir is False, otherwise we remove the installation
20832103 """
20842104 if not self .build_in_installdir and build_option ('cleanup_builddir' ):
2085- try :
2086- os .chdir (self .orig_workdir ) # make sure we're out of the dir we're removing
20872105
2088- self .log .info ("Cleaning up builddir %s (in %s)" % (self .builddir , os .getcwd ()))
2106+ # make sure we're out of the dir we're removing
2107+ change_dir (self .orig_workdir )
2108+ self .log .info ("Cleaning up builddir %s (in %s)" , self .builddir , os .getcwd ())
20892109
2110+ try :
20902111 rmtree2 (self .builddir )
20912112 base = os .path .dirname (self .builddir )
20922113
@@ -2137,7 +2158,6 @@ def make_module_step(self, fake=False):
21372158 self .dry_run_msg ("Generating module file %s, with contents:\n " , mod_filepath )
21382159 for line in txt .split ('\n ' ):
21392160 self .dry_run_msg (' ' * 4 + line )
2140-
21412161 else :
21422162 write_file (mod_filepath , txt )
21432163 self .log .info ("Module file %s written: %s" , mod_filepath , txt )
@@ -2162,6 +2182,9 @@ def make_module_step(self, fake=False):
21622182 if not fake :
21632183 self .make_devel_module ()
21642184
2185+ if build_option ('set_default_module' ):
2186+ self ._set_module_as_default ()
2187+
21652188 return modpath
21662189
21672190 def permissions_step (self ):
@@ -2218,7 +2241,7 @@ def test_cases_step(self):
22182241 Run provided test cases.
22192242 """
22202243 for test in self .cfg ['tests' ]:
2221- os . chdir (self .orig_workdir )
2244+ change_dir (self .orig_workdir )
22222245 if os .path .isabs (test ):
22232246 path = test
22242247 else :
@@ -2514,7 +2537,7 @@ def build_and_install_one(ecdict, init_env):
25142537 ended = 'ended'
25152538
25162539 # make sure we're back in original directory before we finish up
2517- os . chdir (cwd )
2540+ change_dir (cwd )
25182541
25192542 application_log = None
25202543
@@ -2709,7 +2732,7 @@ def perform_step(step, obj, method, logfile):
27092732 start_time = time .time ()
27102733
27112734 # start with a clean slate
2712- os . chdir (base_dir )
2735+ change_dir (base_dir )
27132736 restore_env (base_env )
27142737 sanitize_env ()
27152738
0 commit comments