diff --git a/.hunspell.en.dic b/.hunspell.en.dic index 7482eb4aa..d6b1d9785 100644 --- a/.hunspell.en.dic +++ b/.hunspell.en.dic @@ -492,6 +492,7 @@ gh ghcommit gitlog gmake +gpt grp gz gzip diff --git a/NEWS.rst b/NEWS.rst index b30b07019..10383be0a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -251,6 +251,9 @@ Modules 5.7.0 (not yet released) * Doc: add the :ref:`user-guide` document that explains a selection of useful but lesser known features through practical examples and common use cases. +* Keep non-sticky requirements of sticky modules loaded during a + :subcmd:`purge` and explicitly report why their unload is skipped according + to the :mconfig:`sticky_purge` configuration. (fix issue #582) .. _5.6 release notes: diff --git a/tcl/modeval.tcl b/tcl/modeval.tcl index 0d59392b5..b527411d6 100644 --- a/tcl/modeval.tcl +++ b/tcl/modeval.tcl @@ -959,6 +959,19 @@ proc isModuleSticky {mod} { $mod sticky 1] && ![getState force])}] } +proc getModuleStickyDependentTag {mod} { + set sticky_tag {} + foreach dep_mod [getDependentLoadedModuleList [list $mod] 1 0 0 0] { + if {[isModuleTagged $dep_mod super-sticky 1]} { + set sticky_tag super-sticky + break + } elseif {![getState force] && [isModuleTagged $dep_mod sticky 1]} { + set sticky_tag sticky + } + } + return $sticky_tag +} + proc saveLoadedReqOfUnloadingModule {unload_mod} { # fetch requirements of unloading module set ::g_savedLoReqOfUnloadMod($unload_mod)\ @@ -1172,6 +1185,21 @@ proc failOrSkipUnloadIfSticky {modname modfile} { return 0 } +proc failOrSkipUnloadIfRequiredBySticky {mod} { + set sticky_tag [getModuleStickyDependentTag $mod] + if {$sticky_tag eq {}} { + return 0 + } + + set msg [getStickyReqUnloadMsg $sticky_tag] + switch -- [getConf sticky_purge] { + error {knerror $msg} + warning {reportWarning $msg} + } + + return 1 +} + # ;;; Local Variables: # ;;; Mode: tcl-mode # ;;; tcl-indent-level: 3 diff --git a/tcl/report.tcl.in b/tcl/report.tcl.in index 2938a7824..45af25258 100644 --- a/tcl/report.tcl.in +++ b/tcl/report.tcl.in @@ -1115,6 +1115,10 @@ proc getStickyUnloadMsg {{tag sticky}} { return "Unload of $tag module skipped" } +proc getStickyReqUnloadMsg {{tag sticky}} { + return "Unload skipped because module is required by a $tag module" +} + proc getStickyForcedUnloadMsg {} { return {Unload of sticky module forced} } diff --git a/tcl/subcmd.tcl.in b/tcl/subcmd.tcl.in index 36c733d61..a6a110609 100644 --- a/tcl/subcmd.tcl.in +++ b/tcl/subcmd.tcl.in @@ -1577,6 +1577,11 @@ proc cmdModuleUnload {context match auto force onlyureq args} { set prereq_list [getDependentLoadedModuleList [list $modname]] set prereq_loaded_list [getDependentLoadedModuleList [list $modname]\ 1 1 0 0] + if {[llength $prereq_loaded_list] &&\ + [getState commandname] eq {purge} &&\ + [failOrSkipUnloadIfRequiredBySticky $modname]} { + continue + } if {[llength $prereq_loaded_list] && (![getConf auto_handling] ||\ !$auto)} { # force mode should not affect if we only look for mods w/o dep diff --git a/testsuite/modules.00-init/005-init_ts.exp b/testsuite/modules.00-init/005-init_ts.exp index 34dbdacc3..d93a300e2 100644 --- a/testsuite/modules.00-init/005-init_ts.exp +++ b/testsuite/modules.00-init/005-init_ts.exp @@ -455,6 +455,14 @@ set warn_stickyunload "$::warn_msgs: Unload of sticky module skipped" set err_stickyunloadf "$::warn_msgs: Unload of sticky module forced" set err_superstickyunload "$::error_msgs: Unload of super-sticky module skipped" set warn_superstickyunload "$::warn_msgs: Unload of super-sticky module skipped" +set err_stickyrequnload "$::error_msgs: Unload skipped because module is\ + required by a sticky module" +set warn_stickyrequnload "$::warn_msgs: Unload skipped because module is\ + required by a sticky module" +set err_superstickyrequnload "$::error_msgs: Unload skipped because module\ + is required by a super-sticky module" +set warn_superstickyrequnload "$::warn_msgs: Unload skipped because module\ + is required by a super-sticky module" set err_reqfull "$::error_msgs: Module version must be specified to load module" set err_nomodloaded "$error_msgs: $msg_nomodloaded" set err_modfromdiffpathloaded "$error_msgs: Module already loaded from a different modulepath" diff --git a/testsuite/modules.50-cmds/464-sticky_purge.exp b/testsuite/modules.50-cmds/464-sticky_purge.exp index dc14ea1fa..496897a2c 100644 --- a/testsuite/modules.50-cmds/464-sticky_purge.exp +++ b/testsuite/modules.50-cmds/464-sticky_purge.exp @@ -97,6 +97,40 @@ testouterr_cmd sh {purge} $ans {} testouterr_cmd sh {purge -f} $ans {} +# super-sticky module with non-sticky requirement +setenv_var TESTSUITE_STICKY purge_req +setenv_loaded_module [list sticky1/1.0 sticky2/1.0] [list\ + $mp/sticky1/1.0 $mp/sticky2/1.0] +setenv_var __MODULES_LMTAG sticky2/1.0&super-sticky +setenv_var __MODULES_LMPREREQ sticky2/1.0&sticky1/1.0|sticky1/2.0 + +set ans [list] +lappend ans [list set _LMFILES_ $mp/sticky1/1.0:$mp/sticky2/1.0] +lappend ans [list set LOADEDMODULES sticky1/1.0:sticky2/1.0] + +setenv_var MODULES_STICKY_PURGE error +set anserr $ans +lappend anserr [list ERR] +set tserr [msg_unload {sticky2/1.0 }\ + $err_superstickyunload]\n\n[msg_unload sticky1/1.0\ + $err_superstickyrequnload] +testouterr_cmd sh {purge} $anserr $tserr +testouterr_cmd sh {purge -f} $anserr $tserr + +setenv_var MODULES_STICKY_PURGE warning +set tserr [msg_unload {sticky2/1.0 }\ + $warn_superstickyunload]\n\n[msg_unload sticky1/1.0\ + $warn_superstickyrequnload] +testouterr_cmd sh {purge} $ans $tserr +testouterr_cmd sh {purge -f} $ans $tserr + +setenv_var MODULES_STICKY_PURGE silent +testouterr_cmd sh {purge} $ans {} +testouterr_cmd sh {purge -f} $ans {} + +unsetenv_var TESTSUITE_STICKY + + # module both sticky and super-sticky setenv_var TESTSUITE_FPMOD_TAG sticky2 setenv_loaded_module [list foo/1.0 tag/1.0] [list $mp/foo/1.0 $mp/tag/1.0]