diff --git a/README.new b/README.new index 0ae21c4e4..68857f4c9 100644 --- a/README.new +++ b/README.new @@ -125,3 +125,7 @@ Lmod 8.7+ * TACC issue: Change the current version of zsh with the string ${ZSH_VERSION} when builting the init/zsh file. (8.7.34) * TACC issue: (Again) Cannot use the string ${ZSH_VERSION} in $FPATH. Instead change orig zsh version to current one. +W.I.P + (8.7.35) * Call build_i18n before calling warnings, errors or messages + * PR #696: Allow for multiple hooks. Note that last one in list sets the result value on return + diff --git a/messageDir/en.lua b/messageDir/en.lua index e4e278451..747deedd4 100644 --- a/messageDir/en.lua +++ b/messageDir/en.lua @@ -325,6 +325,7 @@ MODULEPATH directory: "%{mpath}" has too many non-modulefiles (%{regularFn}). Pl ]==], w_Undef_MPATH = "MODULEPATH is undefined.\n", w_Unknown_Hook = "Unknown hook: %{name}\n", + w_Unknown_Hook_Action = "Unknown hook action: %{action}\n", -------------------------------------------------------------------------- diff --git a/rt/hook/SitePackage.lua b/rt/hook/SitePackage.lua deleted file mode 100644 index 09b9ea068..000000000 --- a/rt/hook/SitePackage.lua +++ /dev/null @@ -1,28 +0,0 @@ -require("strict") -require("serializeTbl") -local hook = require("Hook") - -function load_hook(t) - --io.stderr:write("module name: ",t.modName," full module name: ", t.modFullName, " fn: ", t.fn, "\n") - - local moduleInfoT = { modFullName=t.modFullName, fn=t.fn} - local s = serializeTbl{indent = true, name="moduleInfoT", value=moduleInfoT} - local uuid = UUIDString(os.time()) - local dirN = pathJoin(os.getenv("HOME"), ".lmod.d", ".save") - local fn = pathJoin(dirN, uuid .. ".lua") - - if (not isDir(dirN)) then - mkdir_recursive(dirN) - end - - local f = io.open(fn,"w") - if (f) then - f:write(s) - f:close() - end -end - - -hook.register("load",load_hook) - - diff --git a/rt/hook/append/SitePackage.lua b/rt/hook/append/SitePackage.lua new file mode 100644 index 000000000..a72eff845 --- /dev/null +++ b/rt/hook/append/SitePackage.lua @@ -0,0 +1,9 @@ +local hook = require("Hook") + +require("test_hooks") + +hook.register("load",load_hook_a,"append") +hook.register("load",load_hook_b,"append") + + + diff --git a/rt/hook/append/test_hooks.lua b/rt/hook/append/test_hooks.lua new file mode 120000 index 000000000..80adeedbf --- /dev/null +++ b/rt/hook/append/test_hooks.lua @@ -0,0 +1 @@ +../test_hooks.lua \ No newline at end of file diff --git a/rt/hook/err.txt b/rt/hook/err.txt index 109c57265..f2e559e90 100644 --- a/rt/hook/err.txt +++ b/rt/hook/err.txt @@ -2,7 +2,7 @@ step 1 lua ProjectDIR/src/lmod.in.lua shell --regression_testing --version =========================== -Modules based on Lua: Version 8.6.9 2022-02-02 11:25 -04:00 +Modules based on Lua: Version 8.7.34 2024-01-05 19:34 -07:00 by Robert McLay mclay@tacc.utexas.edu =========================== step 2 @@ -12,3 +12,27 @@ lua ProjectDIR/src/lmod.in.lua shell --regression_testing use -a ProjectDIR/rt/h step 3 lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel =========================== +Load hook B called on admin +Load hook B called on intel +=========================== +step 4 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel +=========================== +Load hook B called on admin +Load hook B called on intel +=========================== +step 5 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel +=========================== +Load hook A called on admin +Load hook B called on admin +Load hook A called on intel +Load hook B called on intel +=========================== +step 6 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel +=========================== +Load hook B called on admin +Load hook A called on admin +Load hook B called on intel +Load hook A called on intel diff --git a/rt/hook/hook.tdesc b/rt/hook/hook.tdesc index 64352f498..209eb3a74 100644 --- a/rt/hook/hook.tdesc +++ b/rt/hook/hook.tdesc @@ -23,13 +23,19 @@ testdescript = { MODULEPATH_ROOT=$(testDir)/mf; export MODULEPATH_ROOT LMOD_PREPEND_BLOCK=yes; export LMOD_PREPEND_BLOCK - LMOD_PACKAGE_PATH=$(testDir); export LMOD_PACKAGE_PATH + export LMOD_PACKAGE_PATH=$(testDir)/orig_hook_style; rm -fr _stderr.* _stdout.* err.* out.* .lmod.d .cache .config runLmod --version # 1 runLmod use -a $(testDir)/mf/Core # 2 runLmod load admin intel # 3 + export LMOD_PACKAGE_PATH=$(testDir)/replace + runLmod load admin intel # 4 + export LMOD_PACKAGE_PATH=$(testDir)/append + runLmod load admin intel # 5 + export LMOD_PACKAGE_PATH=$(testDir)/prepend + runLmod load admin intel # 6 HOME=$ORIG_HOME cat _stdout.[0-9][0-9][0-9] > _stdout.orig diff --git a/rt/hook/orig_hook_style/SitePackage.lua b/rt/hook/orig_hook_style/SitePackage.lua new file mode 100644 index 000000000..41162970a --- /dev/null +++ b/rt/hook/orig_hook_style/SitePackage.lua @@ -0,0 +1,8 @@ +local hook = require("Hook") + +require("test_hooks") + +hook.register("load",load_hook_a) +hook.register("load",load_hook_b) + + diff --git a/rt/hook/orig_hook_style/test_hooks.lua b/rt/hook/orig_hook_style/test_hooks.lua new file mode 120000 index 000000000..80adeedbf --- /dev/null +++ b/rt/hook/orig_hook_style/test_hooks.lua @@ -0,0 +1 @@ +../test_hooks.lua \ No newline at end of file diff --git a/rt/hook/out.txt b/rt/hook/out.txt index ace2868a7..ca6527e0b 100644 --- a/rt/hook/out.txt +++ b/rt/hook/out.txt @@ -48,3 +48,75 @@ _LMFILES_=ProjectDIR/rt/hook/mf/Core/admin/admin-1.0.lua:ProjectDIR/rt/hook/mf/C export _LMFILES_; _ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={compiler="intel",},mT={admin={fn="ProjectDIR/rt/hook/mf/Core/admin/admin-1.0.lua",fullName="admin/admin-1.0",loadOrder=1,propT={},stackDepth=0,status="active",userName="admin",wV="^admin.*zfinal-.000000001.*zfinal",},intel={fn="ProjectDIR/rt/hook/mf/Core/intel/intel.lua",fullName="intel/intel",loadOrder=2,propT={},stackDepth=0,status="active",userName="intel",wV="*intel.*zfinal",},},mpathA={"ProjectDIR/rt/hook/mf/Compiler/intel/10.1","ProjectDIR/rt/hook/mf/Core",},}'; export _ModuleTable_; +=========================== +step 4 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel +=========================== +ADMIN_MODULE_LOADED=1; +export ADMIN_MODULE_LOADED; +LD_LIBRARY_PATH=/vol/local/intel/mkl/mkl/lib/lib:/vol/local/intel/idb/idb/lib:/vol/local/intel/fc/fc/lib:/vol/local/intel/cc/cc/lib; +export LD_LIBRARY_PATH; +LMOD_FAMILY_COMPILER=intel; +export LMOD_FAMILY_COMPILER; +LMOD_FAMILY_COMPILER_VERSION=intel; +export LMOD_FAMILY_COMPILER_VERSION; +MANPATH=/vol/local/intel/mkl/mkl/man:/vol/local/intel/idb/idb/man:/vol/local/intel/fc/fc/man:/vol/local/intel/cc/cc/man; +export MANPATH; +MKL_DIR=/vol/local/intel/mkl/mkl/lib/lib; +export MKL_DIR; +MKL_INCLUDE=/vol/local/intel/mkl/mkl/include; +export MKL_INCLUDE; +MODULEPATH=ProjectDIR/rt/hook/mf/Compiler/intel/10.1:ProjectDIR/rt/hook/mf/Core; +export MODULEPATH; +PATH=/vol/local/intel/idb/idb/bin:/vol/local/intel/fc/fc/bin:/vol/local/intel/cc/cc/bin:/usr/sbin:/sbin:ProjectDIR/proj_mgmt:PATH_to_TM; +export PATH; +_ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={compiler="intel",},mT={admin={fn="ProjectDIR/rt/hook/mf/Core/admin/admin-1.0.lua",fullName="admin/admin-1.0",loadOrder=1,propT={},stackDepth=0,status="active",userName="admin",wV="^admin.*zfinal-.000000001.*zfinal",},intel={fn="ProjectDIR/rt/hook/mf/Core/intel/intel.lua",fullName="intel/intel",loadOrder=2,propT={},stackDepth=0,status="active",userName="intel",wV="*intel.*zfinal",},},mpathA={"ProjectDIR/rt/hook/mf/Compiler/intel/10.1","ProjectDIR/rt/hook/mf/Core",},}'; +export _ModuleTable_; +=========================== +step 5 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel +=========================== +ADMIN_MODULE_LOADED=1; +export ADMIN_MODULE_LOADED; +LD_LIBRARY_PATH=/vol/local/intel/mkl/mkl/lib/lib:/vol/local/intel/idb/idb/lib:/vol/local/intel/fc/fc/lib:/vol/local/intel/cc/cc/lib; +export LD_LIBRARY_PATH; +LMOD_FAMILY_COMPILER=intel; +export LMOD_FAMILY_COMPILER; +LMOD_FAMILY_COMPILER_VERSION=intel; +export LMOD_FAMILY_COMPILER_VERSION; +MANPATH=/vol/local/intel/mkl/mkl/man:/vol/local/intel/idb/idb/man:/vol/local/intel/fc/fc/man:/vol/local/intel/cc/cc/man; +export MANPATH; +MKL_DIR=/vol/local/intel/mkl/mkl/lib/lib; +export MKL_DIR; +MKL_INCLUDE=/vol/local/intel/mkl/mkl/include; +export MKL_INCLUDE; +MODULEPATH=ProjectDIR/rt/hook/mf/Compiler/intel/10.1:ProjectDIR/rt/hook/mf/Core; +export MODULEPATH; +PATH=/vol/local/intel/idb/idb/bin:/vol/local/intel/fc/fc/bin:/vol/local/intel/cc/cc/bin:/usr/sbin:/sbin:ProjectDIR/proj_mgmt:PATH_to_TM; +export PATH; +_ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={compiler="intel",},mT={admin={fn="ProjectDIR/rt/hook/mf/Core/admin/admin-1.0.lua",fullName="admin/admin-1.0",loadOrder=1,propT={},stackDepth=0,status="active",userName="admin",wV="^admin.*zfinal-.000000001.*zfinal",},intel={fn="ProjectDIR/rt/hook/mf/Core/intel/intel.lua",fullName="intel/intel",loadOrder=2,propT={},stackDepth=0,status="active",userName="intel",wV="*intel.*zfinal",},},mpathA={"ProjectDIR/rt/hook/mf/Compiler/intel/10.1","ProjectDIR/rt/hook/mf/Core",},}'; +export _ModuleTable_; +=========================== +step 6 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load admin intel +=========================== +ADMIN_MODULE_LOADED=1; +export ADMIN_MODULE_LOADED; +LD_LIBRARY_PATH=/vol/local/intel/mkl/mkl/lib/lib:/vol/local/intel/idb/idb/lib:/vol/local/intel/fc/fc/lib:/vol/local/intel/cc/cc/lib; +export LD_LIBRARY_PATH; +LMOD_FAMILY_COMPILER=intel; +export LMOD_FAMILY_COMPILER; +LMOD_FAMILY_COMPILER_VERSION=intel; +export LMOD_FAMILY_COMPILER_VERSION; +MANPATH=/vol/local/intel/mkl/mkl/man:/vol/local/intel/idb/idb/man:/vol/local/intel/fc/fc/man:/vol/local/intel/cc/cc/man; +export MANPATH; +MKL_DIR=/vol/local/intel/mkl/mkl/lib/lib; +export MKL_DIR; +MKL_INCLUDE=/vol/local/intel/mkl/mkl/include; +export MKL_INCLUDE; +MODULEPATH=ProjectDIR/rt/hook/mf/Compiler/intel/10.1:ProjectDIR/rt/hook/mf/Core; +export MODULEPATH; +PATH=/vol/local/intel/idb/idb/bin:/vol/local/intel/fc/fc/bin:/vol/local/intel/cc/cc/bin:/usr/sbin:/sbin:ProjectDIR/proj_mgmt:PATH_to_TM; +export PATH; +_ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={compiler="intel",},mT={admin={fn="ProjectDIR/rt/hook/mf/Core/admin/admin-1.0.lua",fullName="admin/admin-1.0",loadOrder=1,propT={},stackDepth=0,status="active",userName="admin",wV="^admin.*zfinal-.000000001.*zfinal",},intel={fn="ProjectDIR/rt/hook/mf/Core/intel/intel.lua",fullName="intel/intel",loadOrder=2,propT={},stackDepth=0,status="active",userName="intel",wV="*intel.*zfinal",},},mpathA={"ProjectDIR/rt/hook/mf/Compiler/intel/10.1","ProjectDIR/rt/hook/mf/Core",},}'; +export _ModuleTable_; diff --git a/rt/hook/prepend/SitePackage.lua b/rt/hook/prepend/SitePackage.lua new file mode 100644 index 000000000..365efdb92 --- /dev/null +++ b/rt/hook/prepend/SitePackage.lua @@ -0,0 +1,9 @@ +local hook = require("Hook") + +require("test_hooks") + +hook.register("load",load_hook_a,"prepend") +hook.register("load",load_hook_b,"prepend") + + + diff --git a/rt/hook/prepend/test_hooks.lua b/rt/hook/prepend/test_hooks.lua new file mode 120000 index 000000000..80adeedbf --- /dev/null +++ b/rt/hook/prepend/test_hooks.lua @@ -0,0 +1 @@ +../test_hooks.lua \ No newline at end of file diff --git a/rt/hook/replace/SitePackage.lua b/rt/hook/replace/SitePackage.lua new file mode 100644 index 000000000..724a66bad --- /dev/null +++ b/rt/hook/replace/SitePackage.lua @@ -0,0 +1,9 @@ +local hook = require("Hook") + +require("test_hooks") + +hook.register("load",load_hook_a,"replace") +hook.register("load",load_hook_b,"replace") + + + diff --git a/rt/hook/replace/test_hooks.lua b/rt/hook/replace/test_hooks.lua new file mode 120000 index 000000000..80adeedbf --- /dev/null +++ b/rt/hook/replace/test_hooks.lua @@ -0,0 +1 @@ +../test_hooks.lua \ No newline at end of file diff --git a/rt/hook/test_hooks.lua b/rt/hook/test_hooks.lua new file mode 100644 index 000000000..ba1b5a7b6 --- /dev/null +++ b/rt/hook/test_hooks.lua @@ -0,0 +1,13 @@ +function load_hook_a(t) + local frameStk = require("FrameStk"):singleton() + local mt = frameStk:mt() + local simpleName = string.match(t.modFullName, "(.-)/") + LmodMessage("Load hook A called on " .. simpleName) +end + +function load_hook_b(t) + local frameStk = require("FrameStk"):singleton() + local mt = frameStk:mt() + local simpleName = string.match(t.modFullName, "(.-)/") + LmodMessage("Load hook B called on " .. simpleName) +end diff --git a/src/Hook.lua b/src/Hook.lua index d75a4f5b9..bd2f0651d 100644 --- a/src/Hook.lua +++ b/src/Hook.lua @@ -43,57 +43,74 @@ local M={} local validT = { - ['load'] = false, -- This load hook is called after a - -- modulefile is loaded. - unload = false, -- This unload hook is called after a - -- modulefile is unloaded. - parse_updateFn = false, -- This hook returns the time on the - -- timestamp file. - writeCache = false, -- This hook return whether a cache - -- should be written. - SiteName = false, -- Hook to specify Site Name - -- It is used to generate family - -- prefix: site_FAMILY_ - msgHook = false, -- Hook to print messages after: - -- avail, list, spider, - errWarnMsgHook = false, -- Hook to print messages after LmodError - -- LmodWarning, LmodMessage - groupName = false, -- This hook adds the arch and os name - -- to moduleT.lua to make it safe on - -- shared filesystems. - avail = false, -- Map directory names to labels - category = false, -- Hook to change output of category - restore = false, -- This hook is run after restore operation - startup = false, -- This hook is run when Lmod is called - finalize = false, -- This hook is run just before Lmod generates its output before exiting - packagebasename = false, -- Hook to find the patterns that spider uses for reverse map - load_spider = false, -- This hook is run evaluating modules for spider/avail - listHook = false, -- This hook gets the list of active modules - isVisibleHook = false, -- Called to evalate if a module should be hidden or not - spider_decoration = false, -- This hook adds decoration to spider level one output. - -- It can be the category or a property. - reverseMapPathFilter = false, -- This hook returns two arrays keepA, ignoreA to keep or - -- ignore a path in the reverseMap mapping - colorize_fullName = false, -- Allow module avail and list to colorize name and/or version - + ['load'] = {}, -- This load hook is called after a + -- modulefile is loaded. + unload = {}, -- This unload hook is called after a + -- modulefile is unloaded. + parse_updateFn = {}, -- This hook returns the time on the + -- timestamp file. + writeCache = {}, -- This hook return whether a cache + -- should be written. + SiteName = {}, -- Hook to specify Site Name + -- It is used to generate family + -- prefix: site_FAMILY_ + msgHook = {}, -- Hook to print messages after: + -- avail, list, spider, + errWarnMsgHook = {}, -- Hook to print messages after LmodError + -- LmodWarning, LmodMessage + groupName = {}, -- This hook adds the arch and os name + -- to moduleT.lua to make it safe on + -- shared filesystems. + avail = {}, -- Map directory names to labels + category = {}, -- Hook to change output of category + restore = {}, -- This hook is run after restore operation + startup = {}, -- This hook is run when Lmod is called + finalize = {}, -- This hook is run just before Lmod generates its output before exiting + packagebasename = {}, -- Hook to find the patterns that spider uses for reverse map + load_spider = {}, -- This hook is run evaluating modules for spider/avail + listHook = {}, -- This hook gets the list of active modules + isVisibleHook = {}, -- Called to evalate if a module should be hidden or not + spider_decoration = {}, -- This hook adds decoration to spider level one output. + -- It can be the category or a property. + reverseMapPathFilter = {}, -- This hook returns two arrays keepA, ignoreA to keep or + -- ignore a path in the reverseMap mapping + colorize_fullName = {}, -- Allow module avail and list to colorize name and/or version } -------------------------------------------------------------------------- -- Checks for a valid hook name and stores it if valid. -- @param name The name of the hook. -- @param func The function to store with it. -function M.register(name, func, append) - if (validT[name] ~= nil) then - -- set default for append to be backwards compatible - append = append or false - -- if append and validT[name] was set before, append. Otherwise, overwrite. - if (append and validT[name]) then - validT[name][#validT[name]+1] = func +local s_actionT = { append = true, prepend = true, replace = true } + +function M.register(name, func, action) + if (validT[name] == nil) then + LmodWarning{msg="w_Unknown_Hook",name = tostring(name)} + return + end + + -- set default for action to be backwards compatible + if (action) then + if (type(action) == "string") then + action = action:lower() else - validT[name] = {func} + action = "append" end else - LmodWarning{msg="w_Unknown_Hook",name = tostring(name)} + action = "replace" + end + + -- Check for a valid action + if (not s_actionT[action]) then + LmodWarning{msg="w_Unknown_Hook_Action",action = tostring(action)} + end + + if (action == "replace") then + validT[name] = {func} + elseif (action == "append") then + validT[name][#validT[name]+1] = func + elseif (action == "prepend") then + table.insert(validT[name],1,func) end end