Top priority environment variable values¶
Multiple modulefiles may alter the same environment variable. It may be wanted that among those modulefiles one should have the priority over the others and the value it sets should persist even if another modulefile loaded after attempts to alter the variable.
When using the setenv
modulefile command, a top priority value
should persist over later setenv tries. On append-path
modulefile
command, this top priority value should stay last position and for
prepend-path
modulefile command, value should stay first position.
Implementation¶
Top priority values are implemented by the use of a site-specific
configuration that supersedes the definition of the setenv
,
append-path
and prepend-path
commands to introduce a --top
argument. This argument enables a value set with this flag on to hold top
priority and thus cannot be altered unless by another top priority value.
For append-path
command, --top
ensure value will stay at last position
in path-like variable. Same goes for prepend-path
where --top
ensure
first position in path-like variable.
# override 'setenv' procedure to add a '--top' optional argument
rename ::setenv ::__setenv
proc setenv {args} {
set topPriority 0
set errArgMsg "wrong # args: should be \"setenv ?--top? var val\""
switch -- [llength $args] {
{3} {
if {[lindex $args 0] eq "--top"} {
set topPriority 1
} else {
error $errArgMsg
}
set var [lindex $args 1]
set val [lindex $args 2]
}
{2} {
set var [lindex $args 0]
set val [lindex $args 1]
}
default {
error $errArgMsg
}
}
if {$topPriority} {
# define an helper variable to know a top-priority value has been set
if {[currentMode] ne "display"} {
__setenv MODULES_PRIORITY_$var $val
}
__setenv $var $val
# set non-priority value only if no top priority value already set
} elseif {![info exists ::env(MODULES_PRIORITY_$var)]} {
__setenv $var $val
}
}
# override 'setenv-un' procedure to interpret the '--top' optional argument
# when setenv is evaluated on an unload mode
rename ::setenv-un ::__setenv-un
proc setenv-un {args} {
set topPriority 0
set errArgMsg "wrong # args: should be \"setenv-un ?--top? var val\""
switch -- [llength $args] {
{3} {
if {[lindex $args 0] eq "--top"} {
set topPriority 1
} else {
error $errArgMsg
}
set var [lindex $args 1]
set val [lindex $args 2]
}
{2} {
set var [lindex $args 0]
set val [lindex $args 1]
}
default {
error $errArgMsg
}
}
if {$topPriority} {
# define an helper variable to know a top-priority value has been set
if {[currentMode] ne "display"} {
__setenv-un MODULES_PRIORITY_$var $val
}
__setenv-un $var $val
# set non-priority value only if no top priority value already set
} elseif {![info exists ::env(MODULES_PRIORITY_$var)]} {
__setenv-un $var $val
}
}
# override 'add-path' procedure to add a '--top' optional argument, which
# will benefit to the 'append-path' and 'prepend-path' modulefile commands
rename ::add-path ::__add-path
proc add-path {pos args} {
set keep_top_priority 0
set arglist [lsearch -all -inline -not -exact $args "--top"]
lassign [eval parsePathCommandArgs "add-path" $arglist] separator\
allow_dup idx_val var path_list
# top priority asked
if {[llength $arglist] != [llength $args]} {
# record this top priority value in an helper variable
__setenv MODULES_PRIORITY_${pos}_$var $path_list
} elseif {[info exists ::env(MODULES_PRIORITY_${pos}_$var)]} {
set keep_top_priority 1
}
# ensure top-priority value keeps first or last position by unloading it
# priority new value addition, then restoring it
if {$keep_top_priority} {
eval __unload-path $var $::env(MODULES_PRIORITY_${pos}_$var)
}
eval __add-path $pos $arglist
if {$keep_top_priority} {
eval __add-path $pos $var $::env(MODULES_PRIORITY_${pos}_$var)
}
}
rename ::unload-path ::__unload-path
proc unload-path {args} {
set arglist [lsearch -all -inline -not -exact $args "--top"]
lassign [eval parsePathCommandArgs "unload-path" $arglist] separator\
allow_dup idx_val var path_list
if {[llength $arglist] != [llength $args]} {
# wipe priority helper variable when unloading top priority value
switch -- [lindex [info level -1] 0] {
{append-path} { set pos "append" }
{prepend-path} { set pos "prepend" }
}
if {[info exists pos]} {
__setenv MODULES_PRIORITY_${pos}_$var $path_list
}
}
eval __unload-path $arglist
}
Compatible with Modules v4.2
Installation¶
Create site-specific configuration directory if it does not exist yet:
$ mkdir /usr/share/Modules/etc
Then copy there the site-specific configuration script of this recipe:
$ cp example/top-priority-values/siteconfig.tcl /usr/share/Modules/etc/
Note
Defined location for the site-specific configuration script may vary from
one installation to another. To determine the expected location for this
file on your setup, check the value of the siteconfig
option on Modules
version 4.3 or above:
$ module config siteconfig
On older version of Modules, check the modulecmd.tcl
script:
$ grep '^set g_siteconfig ' $MODULES_CMD
Usage example¶
With a bar/1
modulefile that sets environment variables in a regular way:
#%Module
# define a regular value for variable
setenv TESTVAR value
# prepend a regular value to a path-like variable
prepend-path TESTPATH prevalue
# append a regular value to a path-like variable
append-path TESTPATH postvalue
And a foo/1
modulefile that sets the same variables than bar/1
but
with the --top
priority flag:
#%Module
# define a value for variable holding top priority (not overwritten by non-top priority value)
setenv --top TESTVAR topvalue
# prepend a value to a path-like variable, value that stays first position
prepend-path --top TESTPATH topprevalue
# append a value to a path-like variable, value that stays last position
append-path --top TESTPATH toppostvalue
Enable the modulepath where the example modulefiles are located:
$ module use example/top-priority-values/modulefiles
Load foo/1
then bar/1
modulefiles and check value of the environment
variable set:
$ module load foo/1 bar/1
$ echo $TESTVAR
topvalue
$ echo $TESTPATH
topprevalue:prevalue:postvalue:toppostvalue