Skip to content

Commit

Permalink
adding depends_on()
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert McLay committed Jul 17, 2017
1 parent e2c5278 commit dd992a8
Show file tree
Hide file tree
Showing 20 changed files with 296 additions and 1 deletion.
71 changes: 71 additions & 0 deletions docs/source/098_dependent_modules.rst
@@ -0,0 +1,71 @@
Dependent Modules
=================

Let's assume that module "X" depends on module "A". There are several
ways to handle module dependency. Inside the "X" modulefile you could
have one of the following choices:

#. Use ``prereq("A")``
#. Use ``load("A")``
#. Use ``always_load("A")``
#. Use ``if (not isloaded("A")) then load("A") end``
#. Use ``if (not isloaded("A")) then always_load("A") end``
#. Use ``depends_on("A")``

Let's examine these choices in order. The main issue for each of
these choices is what happens when module "X" is unloaded.

``prereq("A")``
~~~~~~~~~~~~~~~

This choice is the one you give for sophisticated users. If a user
tried to load module "X" without previously loading "A" then the user
will get a message telling the user that they must load "A" before
loading "X". This way the dependency is explicitly handled by the
user. When the user unloads "X", module "A" will remain loaded.


``load("A")``
~~~~~~~~~~~~~

This choice will always load module "A" on the users behalf. This is
true even if "A" is already loaded. When module "X" is unloaded,
module "A" will be unloaded as well.


``always_load("A")``
~~~~~~~~~~~~~~~~~~~~

This choice will always load module "A" on the users behalf. This is
true even if "A" is already loaded. When module "X" is unloaded,
module "A" will remain loaded.

``if (not isloaded("A")) then load("A") end``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This choice will load module "A" on the users behalf if it not already
loaded. When module "X" is unloaded, module "A" will be unloaded as
well.

``if (not isloaded("A")) then always_load("A") end``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This choice will load module "A" on the users behalf if it not already
loaded. When module "X" is unloaded, module "A" will remain loaded.


``depends_on("A")``
~~~~~~~~~~~~~~~~~~~

This choice loads module "A" on the users behalf if it not already
loaded. When module "X" is unloaded, module "A" will be unloaded if it
is a dependent load. Imagine the following scenario with
depends_on("A")::

$ module purge; module load X; module unload X => unload A
$ module purge; module load A; module load X; module unload X => keep A

Note that Lmod *does not* know that if both module "X" and "Y" depend
on "A". So if a user loads both "X" and "Y" and then unloads "X",
module "A" will be unloaded unless the user has explicitly load "A" on
the command line.
1 change: 1 addition & 0 deletions docs/source/index.rst
Expand Up @@ -83,6 +83,7 @@ Advanced Topics
080_hierarchy
090_configuring_lmod
095_tcl2lua
098_dependent_modules
100_generic_modules
110_lmod_mpi_parallel_filesystem
120_shared_home_directories
Expand Down
55 changes: 55 additions & 0 deletions rt/depends_on/depends_on.tdesc
@@ -0,0 +1,55 @@
-- -*- lua -*-
local testName = "depends_on"

testdescript = {
owner = "rtm",
product = "modules",
description = [[
"depends_on"
]],
keywords = {testName },

active = true,
testName = testName,
job_submit_method = "INTERACTIVE",

runScript = [[
. $(projectDir)/rt/common_funcs.sh
unsetMT
initStdEnvVars
export MODULEPATH=$(testDir)/mf/Core
rm -fr _stderr.* _stdout.* err.* out.* .lmod.d
runLmod --version # 1
runLmod load A C # 2
runLmod list # 3
runLmod unload C # 4
runLmod list # 5
HOME=$ORIG_HOME
cat _stdout.[0-9][0-9][0-9] > _stdout.orig
joinBase64Results -bash _stdout.orig _stdout.new
cleanUp _stdout.new out.txt
cat _stderr.[0-9][0-9][0-9] > _stderr.orig
cleanUp _stderr.orig err.txt
rm -f results.csv
wrapperDiff --csv results.csv $(testDir)/out.txt out.txt
wrapperDiff --csv results.csv $(testDir)/err.txt err.txt
testFinish -r $(resultFn) -t $(runtimeFn) results.csv
]],


blessScript = [[
# perform what is needed
]],

tests = {
{ id='t1'},
},

}
26 changes: 26 additions & 0 deletions rt/depends_on/err.txt
@@ -0,0 +1,26 @@
===========================
step 1
lua ProjectDIR/src/lmod.in.lua bash --regression_testing --version
===========================
Modules based on Lua: Version 7.5.11 2017-07-13 12:46 -05:00
by Robert McLay mclay@tacc.utexas.edu
===========================
step 2
lua ProjectDIR/src/lmod.in.lua bash --regression_testing load A C
===========================
===========================
step 3
lua ProjectDIR/src/lmod.in.lua bash --regression_testing list
===========================
Currently Loaded Modules:
1) A 2) B 3) C
===========================
step 4
lua ProjectDIR/src/lmod.in.lua bash --regression_testing unload C
===========================
===========================
step 5
lua ProjectDIR/src/lmod.in.lua bash --regression_testing list
===========================
Currently Loaded Modules:
1) A
Empty file added rt/depends_on/mf/Core/A.lua
Empty file.
Empty file added rt/depends_on/mf/Core/B.lua
Empty file.
1 change: 1 addition & 0 deletions rt/depends_on/mf/Core/C.lua
@@ -0,0 +1 @@
depends_on("A","B")
44 changes: 44 additions & 0 deletions rt/depends_on/out.txt
@@ -0,0 +1,44 @@
===========================
step 1
lua ProjectDIR/src/lmod.in.lua bash --regression_testing --version
===========================
===========================
step 2
lua ProjectDIR/src/lmod.in.lua bash --regression_testing load A C
===========================
LOADEDMODULES="A:B:C";
export LOADEDMODULES;
MODULEPATH="ProjectDIR/rt/depends_on/mf/Core";
export MODULEPATH;
_LMFILES_="ProjectDIR/rt/depends_on/mf/Core/A.lua:ProjectDIR/rt/depends_on/mf/Core/B.lua:ProjectDIR/rt/depends_on/mf/Core/C.lua";
export _LMFILES_;
_ModuleTable_='_ModuleTable_={["MTversion"]=3,depthT={},family={},mT={A={["fn"]="ProjectDIR/rt/depends_on/mf/Core/A.lua",["fullName"]="A",["loadOrder"]=1,propT={},["stackDepth"]=0,["status"]="active",["userName"]="A",},B={["fn"]="ProjectDIR/rt/depends_on/mf/Core/B.lua",["fullName"]="B",["loadOrder"]=2,propT={},["stackDepth"]=1,["status"]="active",["userName"]="B",},C={["fn"]="ProjectDIR/rt/depends_on/mf/Core/C.lua",["fullName"]="C",["loadOrder"]=3,propT={},["stackDepth"]=0,["status"]="active",["userName"]="C",},},mpathA={"ProjectDIR/rt/depends_on/mf/Core",},["systemBaseMPATH"]="ProjectDIR/rt/depends_on/mf/Core",}';
export _ModuleTable_;
===========================
step 3
lua ProjectDIR/src/lmod.in.lua bash --regression_testing list
===========================
MODULEPATH="ProjectDIR/rt/depends_on/mf/Core";
export MODULEPATH;
_ModuleTable_='_ModuleTable_={["MTversion"]=3,depthT={},family={},mT={A={["fn"]="ProjectDIR/rt/depends_on/mf/Core/A.lua",["fullName"]="A",["loadOrder"]=1,propT={},["stackDepth"]=0,["status"]="active",["userName"]="A",},B={["fn"]="ProjectDIR/rt/depends_on/mf/Core/B.lua",["fullName"]="B",["loadOrder"]=2,propT={},["stackDepth"]=1,["status"]="active",["userName"]="B",},C={["fn"]="ProjectDIR/rt/depends_on/mf/Core/C.lua",["fullName"]="C",["loadOrder"]=3,propT={},["stackDepth"]=0,["status"]="active",["userName"]="C",},},mpathA={"ProjectDIR/rt/depends_on/mf/Core",},["systemBaseMPATH"]="ProjectDIR/rt/depends_on/mf/Core",}';
export _ModuleTable_;
===========================
step 4
lua ProjectDIR/src/lmod.in.lua bash --regression_testing unload C
===========================
LOADEDMODULES="A";
export LOADEDMODULES;
MODULEPATH="ProjectDIR/rt/depends_on/mf/Core";
export MODULEPATH;
_LMFILES_="ProjectDIR/rt/depends_on/mf/Core/A.lua";
export _LMFILES_;
_ModuleTable_='_ModuleTable_={["MTversion"]=3,depthT={},family={},mT={A={["fn"]="ProjectDIR/rt/depends_on/mf/Core/A.lua",["fullName"]="A",["loadOrder"]=1,propT={},["stackDepth"]=0,["status"]="active",["userName"]="A",},},mpathA={"ProjectDIR/rt/depends_on/mf/Core",},["systemBaseMPATH"]="ProjectDIR/rt/depends_on/mf/Core",}';
export _ModuleTable_;
===========================
step 5
lua ProjectDIR/src/lmod.in.lua bash --regression_testing list
===========================
MODULEPATH="ProjectDIR/rt/depends_on/mf/Core";
export MODULEPATH;
_ModuleTable_='_ModuleTable_={["MTversion"]=3,depthT={},family={},mT={A={["fn"]="ProjectDIR/rt/depends_on/mf/Core/A.lua",["fullName"]="A",["loadOrder"]=1,propT={},["stackDepth"]=0,["status"]="active",["userName"]="A",},},mpathA={"ProjectDIR/rt/depends_on/mf/Core",},["systemBaseMPATH"]="ProjectDIR/rt/depends_on/mf/Core",}';
export _ModuleTable_;
1 change: 1 addition & 0 deletions src/MC_Access.lua
Expand Up @@ -106,6 +106,7 @@ M.always_unload = MasterControl.quiet
M.add_property = MasterControl.quiet
M.append_path = MasterControl.quiet
M.conflict = MasterControl.quiet
M.depends_on = MasterControl.quiet
M.error = MasterControl.quiet
M.execute = MasterControl.execute
M.family = MasterControl.quiet
Expand Down
1 change: 1 addition & 0 deletions src/MC_CheckSyntax.lua
Expand Up @@ -50,6 +50,7 @@ M.always_unload = MasterControl.quiet
M.add_property = MasterControl.add_property
M.append_path = MasterControl.append_path
M.conflict = MasterControl.quiet
M.depends_on = MasterControl.depends_on
M.execute = MasterControl.quiet
M.family = MasterControl.quiet
M.help = MasterControl.quiet
Expand Down
7 changes: 7 additions & 0 deletions src/MC_ComputeHash.lua
Expand Up @@ -148,6 +148,13 @@ end
function M.load(self, mA)
A[#A+1] = ShowCmdA("load", mA)
end
--------------------------------------------------------------------------
-- Print depends_on command.
-- @param self A MasterControl object
-- @param mA An array of module names (MName objects)
function M.depends_on(self, mA)
A[#A+1] = ShowCmdA("depends_on", mA)
end

--------------------------------------------------------------------------
-- Print load command.
Expand Down
1 change: 1 addition & 0 deletions src/MC_Load.lua
Expand Up @@ -50,6 +50,7 @@ M.always_unload = MasterControl.unload
M.add_property = MasterControl.add_property
M.append_path = MasterControl.append_path
M.conflict = MasterControl.conflict
M.depends_on = MasterControl.depends_on
M.execute = MasterControl.execute
M.family = MasterControl.family
M.help = MasterControl.quiet
Expand Down
1 change: 1 addition & 0 deletions src/MC_MgrLoad.lua
Expand Up @@ -51,6 +51,7 @@ M.always_unload = MasterControl.fake_load
M.add_property = MasterControl.add_property
M.append_path = MasterControl.append_path
M.conflict = MasterControl.conflict
M.depends_on = MasterControl.fake_load
M.execute = MasterControl.execute
M.family = MasterControl.family
M.help = MasterControl.quiet
Expand Down
1 change: 1 addition & 0 deletions src/MC_Refresh.lua
Expand Up @@ -54,6 +54,7 @@ M.always_unload = MasterControl.quiet
M.add_property = MasterControl.quiet
M.append_path = MasterControl.quiet
M.conflict = MasterControl.quiet
M.depends_on = MasterControl.quiet
M.execute = MasterControl.execute
M.family = MasterControl.quiet
M.help = MasterControl.quiet
Expand Down
7 changes: 7 additions & 0 deletions src/MC_Show.lua
Expand Up @@ -209,6 +209,13 @@ end
function M.load(self, mA)
A[#A+1] = ShowCmdA("load",mA)
end
--------------------------------------------------------------------------
-- Print depends_on command.
-- @param self A MasterControl object
-- @param mA An array of module names (MName objects)
function M.depends_on(self, mA)
A[#A+1] = ShowCmdA("depends_on",mA)
end

M.load_usr = M.load

Expand Down
1 change: 1 addition & 0 deletions src/MC_Spider.lua
Expand Up @@ -59,6 +59,7 @@ local M = MC_Spider
M.always_load = MasterControl.quiet
M.always_unload = MasterControl.quiet
M.conflict = MasterControl.quiet
M.depends_on = MasterControl.quiet
M.error = MasterControl.quiet
M.execute = MasterControl.execute
M.family = MasterControl.quiet
Expand Down
1 change: 1 addition & 0 deletions src/MC_Unload.lua
Expand Up @@ -54,6 +54,7 @@ M.always_unload = MasterControl.unload
M.add_property = MasterControl.remove_property
M.append_path = MasterControl.remove_path_last
M.conflict = MasterControl.quiet
M.depends_on = MasterControl.forgo
M.execute = MasterControl.execute
M.family = MasterControl.unset_family
M.help = MasterControl.quiet
Expand Down
67 changes: 67 additions & 0 deletions src/MasterControl.lua
Expand Up @@ -758,6 +758,73 @@ function M.mustLoad(self)
end


-------------------------------------------------------------------
-- depends_on() a list of modules. This is short hand for:
--
-- if (not isloaded("name")) then load("name") end
--

function M.depends_on(self, mA)
if (dbg.active()) then
local s = mAList(mA)
dbg.start{"MasterControl:depends_on(mA={"..s.."})"}
end

local mB = {}

for i = 1,#mA do
local mname = mA[i]
if (not mname:isloaded()) then
mB[#mB + 1] = mname
end
end

local frameStk = FrameStk:singleton()
if (masterTbl().checkSyntax and frameStk:count() > 1) then
dbg.print{"frameStk:count(): ",frameStk:count(),"\n"}
dbg.fini("MasterControl:depends_on")
return {}
end

registerUserLoads(mB)
local a = self:load(mB)
dbg.fini("MasterControl:depends_on")
return a
end

-------------------------------------------------------------------
-- forgo a list of modules. This is the reverse of depends_on()
--
-- if (not isloaded("name")) then load("name") end
--
-- On unload forgo unloads iff stackDepth is zero.

function M.forgo(self,mA)
local master = Master:singleton()
if (dbg.active()) then
local s = mAList(mA)
dbg.start{"MasterControl:forgo(mA={"..s.."})"}
end

local mt = FrameStk:singleton():mt()
local mB = {}
for i = 1,#mA do
local mname = mA[i]
local sn = mname:sn()
local stackDepth = mt:stackDepth(sn)
if (stackDepth > 0) then
mB[#mB+1] = mname
end
end

unRegisterUserLoads(mB)
local aa = master:unload(mB)
dbg.fini("MasterControl:forgo")
return aa
end



-------------------------------------------------------------------
-- Load a list of modules. Check to see if the user requested
-- modules were actually loaded.
Expand Down
10 changes: 9 additions & 1 deletion src/modfuncs.lua
Expand Up @@ -749,7 +749,15 @@ function always_unload(...)
return b
end

--- Family function ---
function depends_on(...)
dbg.start{"depends_on(",concatTbl({...},", "),")"}
if (not validateStringArgs("depends_on",...)) then return {} end

local b = mcp:depends_on(MName:buildA(mcp:MNameType(),...))
dbg.fini("depends_on")
end

--- subprocess function ---

function subprocess(cmd)
dbg.start{"subprocess(",cmd,")"}
Expand Down
1 change: 1 addition & 0 deletions src/sandbox.lua
Expand Up @@ -98,6 +98,7 @@ sandbox_env = {
try_add = try_load,
unload = unload,
always_load = always_load,
depends_on = depends_on,

--- Load Modify functions ---
atleast = atleast,
Expand Down

0 comments on commit dd992a8

Please sign in to comment.