diff --git a/README.new b/README.new index a05a617e5..dc32f4ea5 100644 --- a/README.new +++ b/README.new @@ -144,7 +144,7 @@ Lmod 8.7+ Namely print the location of the module. * Support for "module --terse spider phdf5/1.12.2" that just prints the module in the hierarchy. * Move almost almost all cosmic:value() calls to inside function not at routine top-level. - * PR: #702: Report build time in UTC when $SOURCE_DATE_EPOCH is set + * PR #702: Report build time in UTC when $SOURCE_DATE_EPOCH is set * PR #679: support for downstream conflicts added * PR #679: support for dynamic LMOD_MODULERC (8.7.39) * Fix busted test for ModuleA. @@ -156,6 +156,5 @@ Lmod 8.7+ * ModuleTable modification: Changes to $MODULEPATH are stored in an entry. (8.7.42) * Fix setting of $FPATH when running bash or ksh shell and executing zsh -l. (8.7.43) * Support for ksh flag not needed anymore - - - +W.I.P: + (8.7.44) * Issue #710: path2pathA() keep double delims, Reduce triple delims to double diff --git a/docs/source/025_new.rst b/docs/source/025_new.rst index f4b66f15e..06176e694 100644 --- a/docs/source/025_new.rst +++ b/docs/source/025_new.rst @@ -1,8 +1,17 @@ New Features in Lmod ==================== +**MODULES_AUTO_DEFAULT** + (Lmod 8.7.41+) When this variable is set then Lmod treats *prereq* + as *depends_on* and *prereq_any* as *depends_on_any*. + +**depends_on_any("pkgA*,"pkgB",...)** + (Lmod 8.7.41+) A new function *depends_on_any()* which works like + *depends_on()* except that Lmod picks the first available in the + list. + **hook.register(, func, )** - (Lmod 8.7.25) The hook.register function now takes a optional third + (Lmod 8.7.25+) The hook.register function now takes a optional third argument: action. The legal actions are the followning strings: "replace", "append", "prepend". See :ref:`registering_multiple_hook_functions-label` for more details. diff --git a/docs/source/090_configuring_lmod.rst b/docs/source/090_configuring_lmod.rst index 0b1827c57..421a68025 100644 --- a/docs/source/090_configuring_lmod.rst +++ b/docs/source/090_configuring_lmod.rst @@ -244,6 +244,11 @@ the configuration option which will set the action. ~/.config/lmod but will check both directories when reading picking the most recent one. +**MODULES_AUTO_HANDLING**: + [yes/no, default: no, --with-modulesAutoHandling]. + When this is set, Lmod will treat *prereq()* like *depends_on()* and + *prereq_any()* like *depends_on_any()*. + Configuration or cosmic:assign() at startup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/098_dependent_modules.rst b/docs/source/098_dependent_modules.rst index 9f633ec55..453222d12 100644 --- a/docs/source/098_dependent_modules.rst +++ b/docs/source/098_dependent_modules.rst @@ -7,7 +7,7 @@ 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 ``depends_on("A","B")`` +#. Use ``depends_on("A","B")`` or ``depends_on_any("C","D", ...)`` #. Use ``prereq("A")`` #. Use ``load("A")`` #. Use ``always_load("A")`` @@ -34,6 +34,17 @@ on "A" then:: $ module purge; module load X Y; module unload X => keep A $ module purge; module load X Y; module unload X Y => unload A + +``depends_on_any("C","D")`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The function ``depends_on_any("C","D")`` works similarly to +``depends_on()`` except that Lmod picks the first available module +listed. It first checks to see if any of the modules are already +loaded. If none are already loaded then picks the first one that can +be loaded. On unload, Lmod remembers which of the choices it loaded +to unload. It is not an error if that module has already been +unloaded. + Complex uses of ``depends_on()`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/250_site_package.rst b/docs/source/250_site_package.rst index 5cb0e9b96..3262aa993 100644 --- a/docs/source/250_site_package.rst +++ b/docs/source/250_site_package.rst @@ -37,7 +37,7 @@ Then inside your /home/user/Lmod/SitePackage.lua do:: require("Site") -Each require statement can only ``require'' one name. So make sure +Each require statement can only ``require`` one name. So make sure that you symlink to a new name in your personal SitePackage.lua directory. Checking if you have setup SitePackage.lua correctly diff --git a/docs/source/410_Lmod_principals.rst b/docs/source/410_Lmod_principals.rst index aa2fbb5e3..f8c36fc9b 100644 --- a/docs/source/410_Lmod_principals.rst +++ b/docs/source/410_Lmod_principals.rst @@ -6,6 +6,34 @@ Module Naming FullName -> shortname/version ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +N/V vs. C/N/V +~~~~~~~~~~~~~ +Lmod supports names like gcc/10.1 where gcc is the shortname and 10.1 +is the version. It also supports C/N/V which is +category/name/version. So a module can be named compiler/gcc/10.1 +where the shortname is compiler/gcc and the version is 10.1. The +number of categories can be as many as a site wants to use. It is +just more typing. Internally, Lmod only separates the fullName into a +shortname (sn) and a version. + +N/V vs. N/V/V +~~~~~~~~~~~~~ + +Starting with version 7+, Lmod support two or more levels of versions +(namely N/V/V). So sites might name a module gcc/x86_64/10.1, where the +shortname is gcc and the version is x86_64/10.1. The depth of version +is unlimited as is the number of names. So a site might name a module: +compiler/gcc/x86_64/10.1 where the shortname is compiler/gcc and the +version is x86_64/10.1 + +See the discussion about consequences of using N/V/V vs. N/V in ... + + + + + + + One Name Rule ~~~~~~~~~~~~~ It is really the one shortname (or sn) rule. A user can only load one @@ -45,7 +73,7 @@ Encoding text strings can be converted to base64 encoding. This means that all spaces and quotes are hidden from shell interpretation. The ModuleTable is encoded as: -_ModuleTable001_ and _ModuleTable_Sz_ +_ModuleTable_Sz_ and _ModuleTable001_ _ModuleTable002_ ... Other environment variables used by Lmod internally all start with __LMOD_ @@ -56,6 +84,130 @@ Lmod communicates with users via a group of env. vars Thing like LMOD_CMD and LMOD_DIR etc. +Lmod coding conventions +~~~~~~~~~~~~~~~~~~~~~~~ + +Notes +~~~~~ + +A discussion on the design of Lmod: + +* At the outermost level. The lmod program produces text. This text + is evaluated by the appropriate tool. In other words, Lmod can + produce shell commands to be evaluated by a shell. It can also + produce python, perl or cmake commands to be evaluate by the + matching tool. + +* Internally, Lmod has a table of key-value pairs that contain + typically environment variables and their values. If no errors are + encountered, then Lmod loops over the keys in alphabetical order and + generates the requested style for output (shell, python, ...). + +* Give an example modulefile: + + $ cat acme/1.1.lua + + setenv( "SITE_ACME_DIR", "/opt/apps/acme/1.1") + prepend_path( "PATH", "/opt/apps/acme/1.1/bin") + prepend_path( "LD_LIBRARY_PATH", "/opt/apps/acme/1.1/bin") + +* $ module load acme + +* Lmod gets the subcommand "load" and converts it to the "Load" (via src/lmod.in.lua) + function in cmdfuncs.lua + + Note all subcommands from the command line map to functions in src/cmdfuncs.lua + +* Steps to load the module: +** Find the modulefile: acme/1.1.lua +** 1st Lmod walks the directories with the src/DirTree.lua to build + DirT table. This table contains the directory tree. +** 2nd: Lmod converts dirT into moduleA +** The conversion into moduleA applies all the rules that Lmod + requires to know the shortname and version. +*** Whether a module is a meta module (i.e. no version) +*** Whether it is a N/V or N/V/V +*** Any marked defaults in the directory tree (as oppose to + LMOD_MODULERC) +* if LMOD_CACHED_LOAD is set then Lmod skips all those step because it + has already found moduleT ( the file is called spiderT but it is + really moduleA) +* If all modules are in the form of N/V (instead of N/V/V) then + moduleT with multiple directories in the module path are joined into + one structure called LocationT + +* Go to spec/*/*_spec.lua to see an example of what the structure looks + like. For exmaple spec/DirTree/DirTree_spec.lua for what dirT looks + like and spec/ModuleA/ModuleA_spec.lua + +* When a module is loaded. All is known is the userName. That is the + name that the module name on the command line. It could be the + fullName (i.e. shortName/version) or just the shortName. + +* That userName is used to initialize on MName object. This object is + used to convert the userName into the fileName. This is a lazy + evaluation. The conversion from a userName into a fullName and + fileName is only done when it is needed. + +* This is because **module load compiler mpi* the mpi modulefiles + location might not be known until the compiler module has been + loaded. + + + +------------------------------------------------------------------------ +Outline of steps to load a modulefile +* command line is parsed into a sub-command such as load +* the load string is converted to an action -> Load_Usr +** Note that all commands are found in src/cmdfuncs.lua +* The operation of Load_Usr and l_usrLoad() are discussed here +* Each positional argument is now a module to load (or unload) +* Each userName of a module is converted to an MName object (and is + discussed here) +* Each Lmod function inside a modulefile gets evaluated differently + depending on the mode. When loading a module, the setenv() function + sets an environment variable. When unloading a module, the setenv() + function unsets or clears the environment variable. + + The various ways that Lmod evaluates its functions is controlled by + the MainControl base class and the derived (or inherited) classes + such as src/MC_Load.lua for module loads and src/MC_Unload.lua + +* So the command load calls Load_Usr() in src/cmdfuncs.lua. That + calls l_usrLoad(). This then calls MainControl:load_usr() which + calls MainControl:load(). This then calls Hub:load() which is doing + the real work of loading a module + +* Hub:load() enforces the rules of Lmod + +* Lmod uses the MName object to convert the userName into a filename. + +* Then the function loadModuleFile() tells Lua to evaluate the + modulefile. It does so by reading the entire contents of the file + into a string. This string is given to Lua to evaluate inside a + sandbox (see details here) +* A tcl modulefile is converted to a lua via tcl2lua.tcl + +* When lua encounters a function like setenv() or prepend_path(), + these functions are Lmod functions. + +* A function like setenv() and prepend_path() are found in src/modfuncs.lua. + These functions check that the arguments are valid. Then + mcp:setenv() is called. + +* Review what mcp:setenv() etc means + +* functions like MainControl:setenv() and MainControl:prepend_path() + sets a key-value pair in the varT table. + +* Explain what frameStk does + +* Once all modulefile(s) are evaluated, control returns to lmod. + Assuming no errors were encountered, then lmod generates text from + the key-value pairs stored in the varT table for the appropriate + "shell". This includes the Moduletable, LOADEDMODULES and _LMFILES_ + +* Hooks? diff --git a/init/lmod_bash_completions b/init/lmod_bash_completions index 1d1286f50..2c80f089f 100644 --- a/init/lmod_bash_completions +++ b/init/lmod_bash_completions @@ -127,7 +127,7 @@ _module() { --quiet --terse --version --default --width -r --regexp --mt --latest \ -I --ignore_cache --gitversion --dumpversion --config --miniConfig \ --timer -f --force --redirect --show_hidden -T --trace --nx \ - --no_extensions" + --no_extensions --loc --location --terse_show_extensions --pod " case "${prev}" in add|load|try-load) @@ -193,7 +193,8 @@ _ml() { opts="-d -D -h -q -t -v -w -s --style --expert --quiet --help -H -f --force \ --quiet --terse --version --default --Verbose --width -r --regexp --mt \ --gitversion --ignore_cache -I --latest --pin_version --trace -T --config \ - --miniConfig --config_json --raw --show_hidden" + --miniConfig --config_json --raw --show_hidden --loc --location \ + --terse_show_extensions --pod" case "${prev}" in rm|remove|unload|switch|swap) diff --git a/init/zsh/_ml b/init/zsh/_ml index 198c96463..842ee284a 100644 --- a/init/zsh/_ml +++ b/init/zsh/_ml @@ -12,9 +12,9 @@ _ml() '(- *)'{--version,-v}'[module command version]' '(-D --debug)'{--debug,-D}'[Send program tracing information to stderr]' '(-I --ignore_cache)'{--ignore_cache,-I}'[Treat the cache file(s) as out-of-date]' - '(-T --trace)'{--style,-s}'[Report major internal actions by Lmod]' + '(-T --trace)'{--trace,-T}'[Report major internal actions by Lmod]' '(-d --default)'{--default,-d}'[List default modules only when used with avail]' - '(-f --force)'{--force,-f}'Force removal of a sticky module or save an empty collection]' + '(-f --force)'{--force,-f}'[Force removal of a sticky module or save an empty collection]' '(-q --quiet)'{--quiet,-q}'[disable verbose messages]' '(-r --regexp)'{--regexp,-r}'[lua regular expression matching]' '(-s --style)'{--style,-s}'[avail output style]' @@ -23,18 +23,21 @@ _ml() '--Verbose[show generated module command]' '--config[display full Lmod configuration]' '--config_json[display full Lmod configuration in json format]' - '--force[force the removal of a sticky module or save an empty collection]' + "--gitversion[Report Lmod's git version]" '--latest[Load latest (ignore default)]' '--location[Print the file location only when using show]' '--miniConfig[display configuration differences from default]' '--mt[display the module table]' '--no_redirect[send messages to stderr]' '--old_style[Use multiple module commands when mixing loads and unload]' + '--pin_version[pin versions when restoring a collection]' + '--pod[generate pod format for manpage generation]' '--raw[Print raw contents of a modulefile when using show]' '--redirect[send messages to stdout]' '--show_hidden[avail and spider will report hidden modules]' '--style[]' '--timer[report run times]' + '--terse_show_extensions[Include module extensions in terse avail output]' ) for arg in $arguments; do diff --git a/init/zsh/_module b/init/zsh/_module index 9b42c255c..6b9abfc2d 100644 --- a/init/zsh/_module +++ b/init/zsh/_module @@ -9,27 +9,30 @@ _module() '(- *)'{--version,-v}'[module command version]' \ '(-D --debug)'{--debug,-D}'[Send program tracing information to stderr]' \ '(-I --ignore_cache)'{--ignore_cache,-I}'[Treat the cache file(s) as out-of-date]' \ + '(-T --trace)'{--trace,-T}'[Report major internal actions by Lmod]' \ '(-d --default)'{--default,-d}'[List default modules only when used with avail]' \ + '(-f --force)'{--force,-f}'[Force removal of a sticky module or save an empty collection]' \ '(-q --quiet)'{--quiet,-q}'[disable verbose messages]' \ '(-r --regexp)'{--regexp,-r}'[lua regular expression matching]' \ '(-s --style)'{--style,-s}'[avail output style]' \ '(-t --terse)'{--terse,-t}'[display avail, list and spider output in short format]' \ '(-w --width)'{--width,-w}'[use given width for max term width]' \ - '--Verbose[show generated module command]' \ '--config[display full Lmod configuration]' \ '--config_json[display full Lmod configuration in json format]' \ - '--force[force the removal of a sticky module or save an empty collection]' \ + "--gitversion[Report Lmod's git version]" \ '--latest[Load latest (ignore default)]' \ '--location[Print the file location only when using show]' \ '--miniConfig[display configuration differences from default]' \ '--mt[display the module table]' \ '--no_redirect[send messages to stderr]' \ - '--old_style[Use multiple module commands when mixing loads and unload]' \ + '--pin_version[pin versions when restoring a collection]' \ + '--pod[generate pod format for manpage generation]' \ '--raw[Print raw contents of a modulefile when using show]' \ '--redirect[send messages to stdout]' \ '--show_hidden[avail and spider will report hidden modules]' \ '--style[]' \ '--timer[report run times]' \ + '--terse_show_extensions[Include module extensions in terse avail output]' \ '*::module command:_module_command' } diff --git a/rt/manpath/err.txt b/rt/manpath/err.txt index 4e41475b3..80cbc60ce 100644 --- a/rt/manpath/err.txt +++ b/rt/manpath/err.txt @@ -2,7 +2,7 @@ step 1 lua ProjectDIR/src/lmod.in.lua shell --regression_testing --version =========================== -Modules based on Lua: Version 8.7.20 2023-03-16 11:43 -05:00 +Modules based on Lua: Version 8.7.43 2024-06-24 15:50 -06:00 by Robert McLay mclay@tacc.utexas.edu =========================== step 2 @@ -28,3 +28,11 @@ lua ProjectDIR/src/lmod.in.lua shell --regression_testing load unix step 7 lua ProjectDIR/src/lmod.in.lua shell --regression_testing unload unix =========================== +=========================== +step 8 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load abc +=========================== +=========================== +step 9 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load def +=========================== diff --git a/rt/manpath/manpath.tdesc b/rt/manpath/manpath.tdesc index a1e07cc87..1f4513e0a 100644 --- a/rt/manpath/manpath.tdesc +++ b/rt/manpath/manpath.tdesc @@ -32,6 +32,10 @@ testdescript = { export MANPATH=/unknown/apps/junk/share/man runLmod load unix # 6 runLmod unload unix # 7 + export MANPATH=/opt/X/man:::/opt/Y/man + runLmod load abc # 8 + runLmod load def # 9 + HOME=$ORIG_HOME diff --git a/rt/manpath/mf/Core/abc/1.0.lua b/rt/manpath/mf/Core/abc/1.0.lua new file mode 100644 index 000000000..8178f8790 --- /dev/null +++ b/rt/manpath/mf/Core/abc/1.0.lua @@ -0,0 +1 @@ +prepend_path("MANPATH","/opt/apps/abc/share/man") diff --git a/rt/manpath/mf/Core/def/2.0.lua b/rt/manpath/mf/Core/def/2.0.lua new file mode 100644 index 000000000..d1bebbbb2 --- /dev/null +++ b/rt/manpath/mf/Core/def/2.0.lua @@ -0,0 +1 @@ +append_path("MANPATH","/opt/apps/def//share/man") diff --git a/rt/manpath/out.txt b/rt/manpath/out.txt index 214bdca9b..130aebe58 100644 --- a/rt/manpath/out.txt +++ b/rt/manpath/out.txt @@ -90,3 +90,35 @@ export MODULEPATH; unset _LMFILES_; _ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={},mT={},mpathA={"ProjectDIR/rt/manpath/mf/Core",},systemBaseMPATH="ProjectDIR/rt/manpath/mf/Core",}'; export _ModuleTable_; +=========================== +step 8 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load abc +=========================== +LOADEDMODULES=abc/1.0; +export LOADEDMODULES; +__LMOD_REF_COUNT_MANPATH=/opt/apps/abc/share/man:1\;/opt/X/man:1\;:1\;/opt/Y/man:1; +export __LMOD_REF_COUNT_MANPATH; +MANPATH=/opt/apps/abc/share/man:/opt/X/man::/opt/Y/man; +export MANPATH; +MODULEPATH=ProjectDIR/rt/manpath/mf/Core; +export MODULEPATH; +_LMFILES_=ProjectDIR/rt/manpath/mf/Core/abc/1.0.lua; +export _LMFILES_; +_ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={},mT={abc={fn="ProjectDIR/rt/manpath/mf/Core/abc/1.0.lua",fullName="abc/1.0",loadOrder=1,propT={},stackDepth=0,status="active",userName="abc",wV="000000001.*zfinal",},},mpathA={"ProjectDIR/rt/manpath/mf/Core",},systemBaseMPATH="ProjectDIR/rt/manpath/mf/Core",}'; +export _ModuleTable_; +=========================== +step 9 +lua ProjectDIR/src/lmod.in.lua shell --regression_testing load def +=========================== +LOADEDMODULES=abc/1.0:def/2.0; +export LOADEDMODULES; +__LMOD_REF_COUNT_MANPATH=/opt/apps/abc/share/man:1\;/opt/X/man:1\;:1\;/opt/Y/man:1\;/opt/apps/def/share/man:1; +export __LMOD_REF_COUNT_MANPATH; +MANPATH=/opt/apps/abc/share/man:/opt/X/man::/opt/Y/man:/opt/apps/def/share/man; +export MANPATH; +MODULEPATH=ProjectDIR/rt/manpath/mf/Core; +export MODULEPATH; +_LMFILES_=ProjectDIR/rt/manpath/mf/Core/abc/1.0.lua:ProjectDIR/rt/manpath/mf/Core/def/2.0.lua; +export _LMFILES_; +_ModuleTable_='_ModuleTable_={MTversion=3,depthT={},family={},mT={abc={fn="ProjectDIR/rt/manpath/mf/Core/abc/1.0.lua",fullName="abc/1.0",loadOrder=1,propT={},stackDepth=0,status="active",userName="abc",wV="000000001.*zfinal",},def={fn="ProjectDIR/rt/manpath/mf/Core/def/2.0.lua",fullName="def/2.0",loadOrder=2,propT={},stackDepth=0,status="active",userName="def",wV="000000002.*zfinal",},},mpathA={"ProjectDIR/rt/manpath/mf/Core",},systemBaseMPATH="ProjectDIR/rt/manpath/mf/Core",}'; +export _ModuleTable_; diff --git a/rt/terse_avail/err.txt b/rt/terse_avail/err.txt index d1e4d2d5f..3a2b4c256 100644 --- a/rt/terse_avail/err.txt +++ b/rt/terse_avail/err.txt @@ -2,7 +2,7 @@ step 1 lua ProjectDIR/src/lmod.in.lua shell --regression_testing --version =========================== -Modules based on Lua: Version 8.7.40 2024-06-11 15:18 -06:00 +Modules based on Lua: Version 8.7.43 2024-06-24 15:50 -06:00 by Robert McLay mclay@tacc.utexas.edu =========================== step 2 @@ -62,11 +62,11 @@ lua ProjectDIR/src/lmod.in.lua shell --regression_testing --terse_show_extension ProjectDIR/rt/terse_avail/mf/Compiler/intel/19: python/ python/3.7 +# CC/3.1 +# DDD/4.1 ProjectDIR/rt/terse_avail/mf/Core: TACC gcc/ gcc/9.4 intel/ intel/19.1 -# CC -# DDD diff --git a/src/Hub.lua b/src/Hub.lua index c5cf4c569..b93fdd99f 100644 --- a/src/Hub.lua +++ b/src/Hub.lua @@ -859,6 +859,7 @@ local function l_availEntry(defaultOnly, label, searchA, defaultT, entry) local fullName = entry.fullName local sn = entry.sn local fn = entry.fn + local provideA = entry.provides if (searchA.n > 0) then found = false for i = 1, searchA.n do @@ -874,7 +875,7 @@ local function l_availEntry(defaultOnly, label, searchA, defaultT, entry) end end if (found) then - return sn, fullName, fn + return sn, fullName, fn, provideA end return nil, nil end @@ -1011,8 +1012,8 @@ function M.overview(self,argA) end availA = regroup_avail_blocks(availStyle, availA) - local providedByT = false - self:terse_avail(mpathA, availA, alias2modT, searchA, showSN, defaultOnly, defaultT, providedByT, aa) + local showModuleExt = false + self:terse_avail(mpathA, availA, alias2modT, searchA, showSN, defaultOnly, defaultT, showModuleExt, aa) local label = "" local a = {} @@ -1141,7 +1142,7 @@ function M.buildExtA(self, searchA, mpathA, providedByT, extA) dbg.fini("Hub:buildExtA()") end -function M.terse_avail(self, mpathA, availA, alias2modT, searchA, showSN, defaultOnly, defaultT, providedByT, a) +function M.terse_avail(self, mpathA, availA, alias2modT, searchA, showSN, defaultOnly, defaultT, showModuleExt, a) dbg.start{"Hub:terse_avail()"} local mrc = MRC:singleton() local optionTbl = optionTbl() @@ -1171,7 +1172,7 @@ function M.terse_avail(self, mpathA, availA, alias2modT, searchA, showSN, defaul local prtSnT = {} -- Mark if we have printed the sn? for i = 1,#A do - local sn, fullName, fn = l_availEntry(defaultOnly, label, searchA, defaultT, A[i]) + local sn, fullName, fn, provideA = l_availEntry(defaultOnly, label, searchA, defaultT, A[i]) if (sn) then if (not prtSnT[sn] and sn ~= fullName and showSN) then prtSnT[sn] = true @@ -1185,6 +1186,11 @@ function M.terse_avail(self, mpathA, availA, alias2modT, searchA, showSN, defaul end end aa[#aa+1] = fullName .. "\n" + if (showModuleExt and provideA and next(provideA) ~= nil ) then + for k = 1,#provideA do + aa[#aa+1] = "# " .. provideA[k] .. "\n" + end + end end end if (next(aa) ~= nil) then @@ -1197,17 +1203,17 @@ function M.terse_avail(self, mpathA, availA, alias2modT, searchA, showSN, defaul -- if providedByT is not false then output - if (providedByT and next(providedByT) ~= nil ) then - - local extA = {} - self:buildExtA(searchA, mpathA, providedByT, extA) - - for i=1,#extA do - a[#a+1] = "#" - a[#a+1] = extA[i][1] - a[#a+1] = "\n" - end - end + --if (providedByT and next(providedByT) ~= nil ) then + -- + -- local extA = {} + -- self:buildExtA(searchA, mpathA, providedByT, extA) + -- + -- for i=1,#extA do + -- a[#a+1] = "#" + -- a[#a+1] = extA[i][1] + -- a[#a+1] = "\n" + -- end + --end dbg.fini("Hub:terse_avail") return a @@ -1253,6 +1259,8 @@ function M.avail(self, argA) local alias2modT = mrc:getAlias2ModT(mpathA) local showSN = not defaultOnly + dbg.printT("availA",availA) + if (showSN) then showSN = argA.n == 0 end @@ -1279,17 +1287,8 @@ function M.avail(self, argA) if (optionTbl.terse or optionTbl.terseShowExtensions) then -------------------------------------------------- -- Terse output - local spiderT = false - local dbT = false - local mpathMapT = false - local providedByT = false - if (optionTbl.terseShowExtensions) then - local cache = Cache:singleton{buildCache=true} - spiderT,dbT, mpathMapT, providedByT = cache:build() - end - self:terse_avail(mpathA, availA, alias2modT, searchA, showSN, - defaultOnly, defaultT, providedByT, a) + defaultOnly, defaultT, optionTbl.terseShowExtensions, a) dbg.fini("Hub:avail") return a diff --git a/src/MainControl.lua b/src/MainControl.lua index 1fb030491..98fc0615c 100644 --- a/src/MainControl.lua +++ b/src/MainControl.lua @@ -313,7 +313,7 @@ end -- @param value the environment variable value. -- @param respect If true, then respect the old value. function M.setenv(self, name, value, respect) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:setenv(\"",name,"\", \"",value,"\", \"", respect,"\")"} @@ -394,7 +394,7 @@ end -- @param name the environment variable name. -- @param value the environment variable value. function M.pushenv(self, name, value) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:pushenv(\"",name,"\", \"",value,"\")"} l_check_for_valid_name("pushenv",name) @@ -450,7 +450,7 @@ end -- @param name the environment variable name. -- @param value the environment variable value. function M.popenv(self, name, value) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:popenv(\"",name,"\", \"",value,"\")"} l_check_for_valid_name("popenv",name) @@ -614,7 +614,7 @@ end -- @param name the environment variable name. -- @param value the environment variable value. function M.set_alias(self, name, value) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:set_alias(\"",name,"\", \"",value,"\")"} l_check_for_valid_alias_name("set_alias",name) @@ -636,7 +636,7 @@ end -- @param name the environment variable name. -- @param value the environment variable value. function M.unset_alias(self, name, value) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:unset_alias(\"",name,"\", \"",value,"\")"} local frameStk = FrameStk:singleton() @@ -656,7 +656,7 @@ end -- @param name the environment variable name. -- @param value the environment variable value. function M.set_shell_function(self, name, bash_function, csh_function) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:set_shell_function(\"",name,"\", \"",bash_function,"\"", "\", \"",csh_function,"\""} @@ -679,7 +679,7 @@ end -- @param name the environment variable name. -- @param value the environment variable value. function M.unset_shell_function(self, name, bash_function, csh_function) - name = name:trim() + name = (name or ""):trim() dbg.start{"MainControl:unset_shell_function(\"",name,"\", \"",bash_function,"\"", "\", \"",csh_function,"\""} @@ -1620,7 +1620,7 @@ function M.add_property(self, name, value) local sn = frameStk:sn() local mt = frameStk:mt() l_check_for_valid_name("add_property",name) - mt:add_property(sn, name:trim(), value) + mt:add_property(sn, (name or ""):trim(), value) end @@ -1634,7 +1634,7 @@ function M.remove_property(self, name, value) local sn = frameStk:sn() local mt = frameStk:mt() l_check_for_valid_name("remove_property",name) - mt:remove_property(sn, name:trim(), value) + mt:remove_property(sn, (name or ""):trim(), value) end diff --git a/src/ModuleA.lua b/src/ModuleA.lua index cfceb7ca4..5de2abaa5 100644 --- a/src/ModuleA.lua +++ b/src/ModuleA.lua @@ -379,7 +379,8 @@ function M.build_availA(self) for fullName, vv in pairs(v.fileT) do if (show_hidden or mrc:isVisible{fullName=fullName,sn=sn,fn=vv.fn}) then icnt = icnt + 1 - A[icnt] = { fullName = fullName, pV = pathJoin(sn,vv.pV), fn = vv.fn, sn = sn, propT = vv.propT} + A[icnt] = { fullName = fullName, pV = pathJoin(sn,vv.pV), fn = vv.fn, sn = sn, + propT = vv.propT, provides = vv.provides} end end end diff --git a/src/ml_cmd.in.lua b/src/ml_cmd.in.lua index 0e31940f6..4ce77408e 100644 --- a/src/ml_cmd.in.lua +++ b/src/ml_cmd.in.lua @@ -147,12 +147,14 @@ function main() ["--latest"] = 0, ["--localvar"]=1, ["--location"]=0, ["--loc"] = 0, - ["--pin_versions"]=0, ["--pin-versions"]=0, ["--mt"] = 0, + ["--pin_versions"]=0, ["--pin-versions"]=0, + ["--pod"] = 0, ["--quiet"] = 0, ["-q"] = 0, ["--redirect"] = 0, ["--no_redirect"] = 0, ["--no-redirect"] = 0, ["--spider_timeout"] = 1, ["--spider-timeout"] = 1, ["--terse"] = 0, ["-t"] = 0, + ["--terse_show_extensions"] = 0, ["--timer"] = 0, ["--trace"] = 0, ["-T"] = 0, ["--version"]=0, ["--versoin"]=0, ["--ver"]=0, ["--v"]=0, ["-v"]=0, diff --git a/src/utils.lua b/src/utils.lua index b90dd903f..0c314ea97 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -595,10 +595,15 @@ function path2pathA(path, delim, clearDoubleSlash) if (path == '') then return { '' } end - local delimPatt = delim .. "+"; + -- If path is /sw1/man::/sw2/man then + -- keep the double delim's + -- However convert /sw1/man:::/sw2/man to + -- /sw1/man::/sw2/man - path = path:gsub(delimPatt,delim) + local delimPatt = delim .. delim .. "+"; + local delimStr = delim .. delim + path = path:gsub(delimPatt,delimStr) local pathA = {} for v in path:split(delim) do