Files
modules/tcl/subcmd.tcl.in
Xavier Delaruelle 2d123840cc Introduce modulepath-label modulefile command
Add modulepath-label modulefile command to define specific label for
designated modulepath. This command can be used in rc files. If a
specific label is set for a modulepath, this string is used instead of
modulepath fully qualified path designation as report list header.

Allow command from modulefile execution context to enable use from
global rc files.
2023-07-09 21:12:36 +02:00

3169 lines
117 KiB
Tcl

##########################################################################
# SUBCMD.TCL, module sub-commands procedures
# Copyright (C) 2002-2004 Mark Lakata
# Copyright (C) 2004-2017 Kent Mein
# Copyright (C) 2016-2023 Xavier Delaruelle
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
##########################################################################
proc cmdModuleList {show_oneperline show_mtime search_match args} {
set json [isStateEqual report_format json]
# load tags from loaded modules
cacheCurrentModules
if {[llength $args] > 0} {
defineModEqProc [isIcase] [getConf extended_default]
# match passed name against any part of loaded module names
set mtest [expr {{contains} in $search_match ? {matchin} : {match}}]
set search_queries $args
# prepare header message which depend if search is performed
set loadedmsg {Currently Loaded Matching Modulefiles}
} else {
set search_queries {}
set loadedmsg {Currently Loaded Modulefiles}
}
set report_indesym [isEltInReport indesym 0]
set report_alias [isEltInReport alias 0]
# build list of loaded modules and symbolics and aliases if reported
set loadedmodlist [list]
foreach mod [getLoadedModulePropertyList name] {
set modfile [getModulefileFromLoadedModule $mod]
set mtime [expr {$show_mtime && [file exists $modfile] ?\
[getFileMtime $modfile] : {}}]
set mod_list($mod) [list modulefile $mtime $modfile]
# fetch symbols from loaded environment information
set modname [file dirname $mod]
set sym_list {}
foreach altname [getLoadedAltname $mod 0 sym] {
# skip non-symbol entry
if {$altname ne $modname} {
lappend sym_list [file tail $altname]
# fill loaded list structure with symbolic versions in case
# indesym report is activated
if {$report_indesym} {
set mod_list($altname) [list version $mod]
lappend loadedmodlist $altname
}
}
}
set ::g_symbolHash($mod) [lsort -dictionary $sym_list]
# fetch aliases from loaded environment information
if {$report_alias} {
foreach altname [getLoadedAltname $mod 0 alias] {
set mod_list($altname) [list alias $mod]
lappend loadedmodlist $altname
}
}
lappend loadedmodlist $mod
}
# filter-out hidden loaded modules unless all module should be seen
if {[getState hiding_threshold] <= 1} {
set newloadedmodlist [list]
foreach mod $loadedmodlist {
if {![isModuleTagged $mod hidden-loaded 1]} {
lappend newloadedmodlist $mod
}
}
set loadedmodlist $newloadedmodlist
}
# same header msg if no module loaded at all whether search is made or not
set noloadedmsg [expr {[llength $loadedmodlist] == 0 ? {No Modulefiles\
Currently Loaded.} : {No Matching Modulefiles Currently Loaded.}}]
# filter loaded modules not matching any of the mod spec passed
if {[llength $args] > 0} {
# include alt name comparison (alias/sym) when checking module name
# depends if alias and/or sym are reported independently
set modeq_altname_mode [switch -- $report_indesym$report_alias {
11 {expr {0}}
10 {expr {7}}
01 {expr {6}}
00 {expr {2}}
}]
set matchlist [list]
foreach mod $loadedmodlist {
foreach pattern $args {
# compare pattern against loaded module, its variant set and its
# alternative names
if {[modEq $pattern $mod $mtest 1 $modeq_altname_mode 1 0 *]} {
lappend matchlist $mod
break
}
}
}
set loadedmodlist $matchlist
}
if {[llength $loadedmodlist] == 0} {
if {!$json && [isEltInReport header]} {
report $noloadedmsg
}
} else {
set one_per_line [expr {$show_mtime || $show_oneperline}]
set show_idx [expr {!$show_mtime && [isEltInReport idx]}]
set header [expr {!$json && [isEltInReport header] ? $loadedmsg :\
{noheader}}]
set theader_cols [list hi Package 39 Versions 19 {Last mod.} 19]
reportModules $search_queries $header {} terse $show_mtime $show_idx\
$one_per_line $theader_cols loaded $loadedmodlist
# display output key
if {!$show_mtime && !$json && [isEltInReport key]} {
displayKey
}
}
}
proc cmdModuleDisplay {args} {
lappendState mode display
set first_report 1
foreach mod $args {
lassign [getPathToModule $mod] modfile modname modnamevr
if {$modfile ne {}} {
# only one separator lines between 2 modules
if {$first_report} {
displaySeparatorLine
set first_report 0
}
report [sgr hi $modfile]:\n
execute-modulefile $modfile $modname modnamevr $mod
displaySeparatorLine
}
}
lpopState mode
}
proc cmdModulePaths {mod} {
set dir_list [getModulePathList exiterronundef]
foreach dir $dir_list {
array unset mod_list
array set mod_list [getModules $dir $mod 0 [list rc_defs_included]]
# prepare list of dirs for alias/symbol target search, will first search
# in currently looked dir, then in other dirs following precedence order
set target_dir_list [list $dir {*}[replaceFromList $dir_list $dir]]
# forcibly enable implicit_default to resolve alias target when it
# points to a directory
setConf implicit_default 1
# build list of modulefile to print
foreach elt [array names mod_list] {
switch -- [lindex $mod_list($elt) 0] {
modulefile {
lappend ::g_return_text $dir/$elt
}
virtual {
lappend ::g_return_text [lindex $mod_list($elt) 2]
}
alias - version {
# resolve alias target
set aliastarget [lindex $mod_list($elt) 1]
lassign [getPathToModule $aliastarget $target_dir_list 0]\
modfile modname modnamevr
# add module target as result instead of alias
if {$modfile ne {} && ![info exists mod_list($modname)]} {
lappend ::g_return_text $modfile
}
}
}
}
# reset implicit_default to restore behavior defined
unsetConf implicit_default
}
# sort results if any and remove duplicates
if {[info exists ::g_return_text]} {
set ::g_return_text [lsort -dictionary -unique $::g_return_text]
} else {
# set empty value to return empty if no result
set ::g_return_text {}
}
}
proc cmdModulePath {mod} {
lassign [getPathToModule $mod] modfile modname modnamevr
# if no result set empty value to return empty
if {$modfile eq {}} {
set ::g_return_text {}
} else {
lappend ::g_return_text $modfile
}
}
proc cmdModuleWhatis {args} {
if {[llength $args] == 0} {
lappend args {}
}
foreach mod $args {
cmdModuleSearch $mod {}
}
}
proc cmdModuleSearch {{mod {}} {search {}}} {
# disable error reporting to avoid modulefile errors
# to mix with valid search results
inhibitErrorReport
set json [isStateEqual report_format json]
set icase [isIcase]
defineModEqProc $icase [getConf extended_default]
lappend searchmod rc_defs_included
if {$mod eq {}} {
lappend searchmod wild
}
set foundmod 0
lappendState mode whatis
set dir_list [getModulePathList exiterronundef]
foreach dir $dir_list {
array unset mod_list
array set mod_list [getModules $dir $mod 0 $searchmod]
array unset interp_list
array set interp_list {}
# forcibly enable implicit_default to resolve alias target when it
# points to a directory
setConf implicit_default 1
# build list of modulefile to interpret
foreach elt [array names mod_list] {
switch -- [lindex $mod_list($elt) 0] {
modulefile {
if {[isModuleTagged $elt forbidden 0 $dir/$elt]} {
# register any error occurring on element matching search
if {[modEq $mod $elt]} {
set err_list($elt) [list accesserr [getForbiddenMsg\
$elt $dir/$elt]]
}
} else {
set interp_list($elt) $dir/$elt
# register module name in a global list (shared across
# modulepaths) to get hints when solving aliases/version
set full_list($elt) 1
}
}
virtual {
if {[isModuleTagged $elt forbidden 0 [lindex $mod_list($elt)\
2]]} {
# register any error occurring on element matching search
if {[modEq $mod $elt]} {
set err_list($elt) [list accesserr [getForbiddenMsg\
$elt [lindex $mod_list($elt) 2]]]
}
} else {
set interp_list($elt) [lindex $mod_list($elt) 2]
set full_list($elt) 1
}
}
alias {
# resolve alias target
set elt_target [lindex $mod_list($elt) 1]
if {![info exists full_list($elt_target)]} {
lassign [getPathToModule $elt_target $dir 0]\
modfile modname modnamevr issuetype issuemsg
# add module target as result instead of alias
if {$modfile ne {} && ![info exists mod_list($modname)]} {
set interp_list($modname) $modfile
set full_list($modname) 1
} elseif {$modfile eq {}} {
# if module target not found in current modulepath add to
# list for global search after initial modulepath lookup
if {[string first {Unable to locate} $issuemsg] == 0} {
set extra_search($modname) [list $dir [modEq $mod\
$elt]]
# register resolution error if alias name matches search
} elseif {[modEq $mod $elt]} {
set err_list($modname) [list $issuetype $issuemsg]
}
}
}
}
version {
# report error of version target if matching query
set elt_target [getArrayKey mod_list [lindex $mod_list($elt)\
1] $icase]
if {[info exists mod_list($elt_target)] && [lindex\
$mod_list($elt_target) 0] in [list invalid accesserr] &&\
[modEq $mod $elt]} {
set err_list($elt_target) $mod_list($elt_target)
} elseif {![info exists mod_list($elt_target)]} {
set extra_search($elt_target) [list $dir [modEq $mod $elt]]
}
}
invalid - accesserr {
# register any error occurring on element matching search
if {[modEq $mod $elt]} {
set err_list($elt) $mod_list($elt)
}
}
}
}
# reset implicit_default to restore behavior defined
unsetConf implicit_default
# in case during modulepath lookup we find an alias target we were
# looking for in previous modulepath, remove this element from global
# search list
foreach elt [array names extra_search] {
if {[info exists full_list($elt)]} {
unset extra_search($elt)
}
}
# save results from this modulepath for interpretation step as there
# is an extra round of search to match missing alias target, we cannot
# process modulefiles found immediately
if {[array size interp_list] > 0} {
set interp_save($dir) [array get interp_list]
}
}
# forcibly enable implicit_default to resolve alias target when it points
# to a directory
setConf implicit_default 1
# find target of aliases in all modulepath except the one already tried
foreach elt [array names extra_search] {
lassign [getPathToModule $elt {} 0 no [lindex $extra_search($elt) 0]]\
modfile modname modnamevr issuetype issuemsg issuefile
# found target so append it to results in corresponding modulepath
if {$modfile ne {}} {
# get belonging modulepath dir depending of module kind
if {[isModuleVirtual $modname $modfile]} {
set dir [findModulepathFromModulefile\
$::g_sourceVirtual($modname)]
} else {
set dir [getModulepathFromModuleName $modfile $modname]
}
array unset interp_list
if {[info exists interp_save($dir)]} {
array set interp_list $interp_save($dir)
}
set interp_list($modname) $modfile
set interp_save($dir) [array get interp_list]
# register resolution error if primal alias name matches search
} elseif {$modfile eq {} && [lindex $extra_search($elt) 1]} {
set err_list($modname) [list $issuetype $issuemsg $issuefile]
}
}
# reset implicit_default to restore behavior defined
unsetConf implicit_default
# prepare string translation to highlight search query string
set matchmodmap [prepareMapToHightlightSubstr $mod]
set matchsearchmap [prepareMapToHightlightSubstr $search]
# interpret all modulefile we got for each modulepath
foreach dir $dir_list {
if {[info exists interp_save($dir)]} {
array unset interp_list
array set interp_list $interp_save($dir)
set foundmod 1
set display_list {}
# interpret every modulefiles obtained to get their whatis text
foreach elt [lsort -dictionary [array names interp_list]] {
set ::g_whatis {}
##nagelfar ignore Suspicious variable name
execute-modulefile $interp_list($elt) $elt $elt $elt 0
# treat whatis as a multi-line text
if {$search eq {} || [regexp -nocase $search $::g_whatis]} {
if {$json} {
lappend display_list [formatListEltToJsonDisplay $elt\
whatis a $::g_whatis 1]
} else {
set eltsgr [string map $matchmodmap $elt]
foreach line $::g_whatis {
set linesgr [string map $matchsearchmap $line]
lappend display_list "[string repeat { } [expr {20 -\
[string length $elt]}]]$eltsgr: $linesgr"
}
}
}
}
displayElementList $dir mp sepline 1 0 0 $display_list
}
}
lpopState mode
setState inhibit_errreport 0
# report errors if a modulefile was searched but not found
if {$mod ne {} && !$foundmod} {
# no error registered means nothing was found to match search
if {![array exists err_list]} {
set err_list($mod) [list none "Unable to locate a modulefile for\
'$mod'"]
}
foreach elt [array names err_list] {
reportIssue {*}$err_list($elt)
}
}
}
# Intermediate procedure between module and cmdModuleSwitch
# Adapt options and arguments depending on context to call cmdModuleSwitch
proc cmdModuleIntSwitch {mode tag_list args} {
# pass 'user asked state' to switch procedure
set uasked [isTopEvaluation]
# CAUTION: it is not recommended to use the `switch` sub-command in
# modulefiles as this command is intended for the command-line for a 2in1
# operation. Could be removed from the modfile scope in a future release.
# Use `module unload` and `module load` commands in modulefiles instead.
if {$uasked || $mode eq {load}} {
cmdModuleSwitch $uasked $tag_list {*}$args
} else {
# find what has been asked for unload and load
lassign $args swunmod swlomod
if {$swlomod eq {} && $swunmod ne {}} {
set swlomod $swunmod
}
# apply same mechanisms than for 'module load' and 'module unload' for
# an unload evaluation: nothing done for switched-off module and unload
# of switched-on module. If auto handling is enabled switched-on module
# is handled via UReqUn mechanism (unless if implicit_requirement has
# been inhibited). Also unloads are triggered by ongoing reload, purge,
# restore, reset, stash or stashpop cmds
if {(![getConf auto_handling] || [getState inhibit_req_record] eq\
[currentState evalid]) && $swlomod ne {} && [aboveCommandName] ni\
[list purge reload restore reset stash stashpop]} {
# unload mod if it was loaded prior this mod, not user asked and not
# required by another loaded module
set modlist [getLoadedModulePropertyList name]
set modidx [lsearch -exact $modlist [currentState modulename]]
if {$modidx != 0} {
set priormodlist [lrange $modlist 0 $modidx]
if {[set unmod [getLoadedMatchingName $swlomod {} 0\
$priormodlist]] ne {}} {
if {[cmdModuleUnload urequn match 1 0 1 1 $unmod]} {
reportWarning "Unload of useless requirement\
[getModuleDesignation loaded $unmod] failed" 1
}
}
}
}
}
}
proc cmdModuleSwitch {uasked tag_list old {new {}}} {
# if a single name is provided it matches for the module to load and in
# this case the module to unload is searched to find the closest match
# (loaded module that shares at least the same root name)
if {$new eq {}} {
set new $old
set unload_match close
} else {
set unload_match match
}
# save orig names to register them as deps if called from modulefile
set argnew $new
if {$new eq $old} {
set argold {}
} else {
set argold $old
}
reportDebug "old='$old' new='$new' (uasked=$uasked)"
# extend requirement recording inhibition to switch subcontext
set inhibit_req_rec [expr {[currentState inhibit_req_record] ==\
[currentState evalid]}]
# record sumup messages from underlying unload/load actions under the same
# switch message record id to report (evaluation messages still go under
# their respective unload/load block
pushMsgRecordId switch-$old-$new-[depthState modulename]
if {$inhibit_req_rec} {
lappendState inhibit_req_record [currentState evalid]
}
# enable unload of sticky mod if stickiness is preserved on swapped-on mod
# need to resolve swapped-off module here to get stickiness details
lassign [getPathToModule $old {} 0 $unload_match] modfile oldmod oldmodvr
set sticky_reload [isStickinessReloading $oldmodvr [list $new]]
set supersticky_reload [isStickinessReloading $oldmodvr [list $new]\
super-sticky]
# do not set sticky or supersticky reload states if swap-on module cannot
# be found
if {$supersticky_reload || $sticky_reload} {
lassign [getPathToModule $new] newmodfile newmod newmodvr
if {$newmodfile eq {}} {
set sticky_reload 0
set supersticky_reload 0
}
}
if {$sticky_reload} {
lappendState reloading_sticky $oldmod
}
if {$supersticky_reload} {
lappendState reloading_supersticky $oldmod
}
##nagelfar implicitvarcmd {cmdModuleUnload swunload *} oldhidden olduasked\
oldmsgrecid deprelist depreisuasked deprevr depreextratag
set ret [cmdModuleUnload swunload $unload_match 1 0 0 0 $old]
if {$sticky_reload} {
lpopState reloading_sticky
}
if {$supersticky_reload} {
lpopState reloading_supersticky
}
# register modulefile to unload as conflict if an unload module is
# mentioned on this module switch command set in a modulefile
set orig_auto_handling [getConf auto_handling]
if {!$uasked && $argold ne {}} {
# skip conflict declaration if old spec matches new as in this case
# switch means *replace loaded version of mod by this specific version*
lassign [getPathToModule $new] newmodfile newmod newmodvr
if {$newmod eq {} || ![modEq $argold $newmod eqstart]} {
# temporarily disable auto handling just to record deps, not to try
# to load or unload them (already tried)
setConf auto_handling 0
catch {conflict $argold}
setConf auto_handling $orig_auto_handling
}
}
# attempt load and depre reload only if unload succeed
if {!$ret} {
if {[info exists depreisuasked]} {
set undepreisuasked $depreisuasked
set undeprevr $deprevr
set undepreextratag $depreextratag
}
##nagelfar implicitvarcmd {cmdModuleLoad swload *} newhidden newmsgrecid
cmdModuleLoad swload $uasked 0 0 $tag_list $new
# merge depre info of unload and load phases
if {[info exists undepreisuasked]} {
set depreisuasked [list {*}$undepreisuasked {*}$depreisuasked]
set deprevr [list {*}$undeprevr {*}$deprevr]
set depreextratag [list {*}$undepreextratag {*}$depreextratag]
}
if {[getConf auto_handling] && [info exists deprelist] && [llength\
$deprelist] > 0} {
# cmdModuleUnload handles the DepUn, UReqUn mechanisms and the unload
# phase of the DepRe mechanism. List of DepRe mods and their user
# asked state is set from cmdModuleUnload procedure to be used here
# for the load phase of the DepRe mechanism.
# Try DepRe load phase: load failure will not lead to switch failure
reloadModuleListLoadPhase deprelist $depreisuasked $deprevr\
$depreextratag 1 {Reload of dependent _MOD_ failed} depre
}
# report a summary of automated evaluations if no error
reportModuleEval
} else {
# initialize dummy load phase msg rec id to query designation
set newmsgrecid {}
}
# report all recorded sumup messages for this evaluation unless both old
# and new modules are set hidden, old was auto loaded and this switch is
# done by a modfile
reportMsgRecord "Switching from [getModuleDesignation $oldmsgrecid {} 2]\
to [getModuleDesignation $newmsgrecid $new 2]" [expr {$oldhidden &&\
!$olduasked && $newhidden && !$uasked}]
popMsgRecordId
if {$inhibit_req_rec} {
lpopState inhibit_req_record
}
# register modulefile to load as prereq when called from modulefile
if {!$uasked && !$ret && $argnew ne {}} {
prereqAnyModfileCmd 0 0 $argnew
}
}
proc cmdModuleSave {{coll default}} {
if {![areModuleConstraintsSatisfied]} {
reportErrorAndExit {Cannot save collection, some module constraints are\
not satistied}
}
# format collection content, version number of modulefile are saved if
# version pinning is enabled
if {[getConf collection_pin_version]} {
set curr_mod_list [getLoadedModuleWithVariantList]
set curr_tag_arrser [getLoadedModuleWithVariantSaveTagArrayList]
} else {
lassign [getSimplifiedLoadedModuleList] curr_mod_list curr_tag_arrser
}
# generate collection content with header indicating oldest Modules version
# compatible with collection syntax
set coll_header [expr {[llength $curr_tag_arrser] > 0 ? {#%Module5.1} :\
{}}]
set save [formatCollectionContent [getModulePathList returnempty 0]\
$curr_mod_list $curr_tag_arrser $coll_header]
if { [string length $save] == 0} {
reportErrorAndExit {Nothing to save in a collection}
}
# get corresponding filename and its directory
lassign [findCollections $coll name] collfile colldesc
set colldir [file dirname $collfile]
if {![file exists $colldir]} {
reportDebug "Creating $colldir"
if {[catch {file mkdir $colldir} errMsg]} {
reportErrorAndExit "Collection directory cannot be created.\n$errMsg"
}
} elseif {![file isdirectory $colldir]} {
reportErrorAndExit "$colldir exists but is not a directory"
}
reportDebug "Saving $collfile"
if {[catch {
set fid [open $collfile w]
puts $fid $save
close $fid
} errMsg ]} {
reportErrorAndExit "Collection $colldesc cannot be saved.\n$errMsg"
}
}
proc cmdModuleRestore {args} {
# distinguish between zero and one argument provided
if {[llength $args] == 0} {
set arg_provided 0
set coll default
} else {
set arg_provided 1
set coll [lindex $args 0]
}
# get corresponding collection, raise error if it does not exist unless
# if no collection name has been provided or if __init__
lassign [findCollections $coll exact [expr {!$arg_provided}]\
$arg_provided] collfile colldesc
# forcibly enable implicit_default to restore colls saved in this mode
setConf implicit_default 1
# fetch collection content and differences compared current environment
lassign [getDiffBetweenCurEnvAndColl $collfile $colldesc] coll_path_list\
coll_mod_list coll_tag_arrser coll_nuasked_list mod_to_unload\
mod_to_load path_to_unuse path_to_use is_tags_diff
array set coll_tag_arr $coll_tag_arrser
# create an eval id to track successful/failed module evaluations
pushMsgRecordId restore-$coll-[depthState modulename] 0
# unload modules one by one (no dependency auto unload)
foreach mod [lreverse $mod_to_unload] {
# test stickiness over full module name version variant designation
if {[set vr [getVariantList $mod 1]] ne {}} {
lassign [parseModuleSpecification 0 0 0 0 $mod {*}$vr] modvr
} else {
set modvr $mod
}
# sticky modules can be unloaded when restoring collection
lappendState unloading_sticky $mod
if {[set supersticky_reload [isStickinessReloading $modvr $mod_to_load\
super-sticky]]} {
lappendState reloading_supersticky $mod
}
cmdModuleUnload unload match 0 0 0 0 $mod
lpopState unloading_sticky
if {$supersticky_reload} {
lpopState reloading_supersticky
}
}
# unuse paths
if {[llength $path_to_unuse] > 0} {
cmdModuleUnuse load {*}[lreverse $path_to_unuse]
}
# since unloading a module may unload other modules or
# paths, what to load/use has to be determined after
# the undo phase, so current situation is fetched again
set curr_path_list [getModulePathList returnempty 0]
set curr_mod_list [getLoadedModulePropertyList name]
set curr_nuasked_list [getTaggedLoadedModuleList auto-loaded]
# update tags sets on the modules already loaded at correct position
# remove extra tags that are not defined in collection
foreach modvr [getLoadedModuleWithVariantList] {
if {[info exists coll_tag_arr($modvr)]} {
set tag_list $coll_tag_arr($modvr)
} else {
set tag_list {}
}
# indicate if module has been asked by user
cmdModuleTag 1 [expr {![isModuleTagged $modvr auto-loaded 1]}]\
$tag_list $modvr
}
# determine what module to load to restore collection from current
# situation with preservation of the load order
# list of alternative and simplified names for loaded modules has been
# gathered and cached during the previous getMovementBetweenList call on
# modules, so here the getMovementBetweenList call will correctly get these
# alternative names for module comparison even if no modulepath is left set
lassign [getMovementBetweenList $curr_mod_list $coll_mod_list\
$curr_nuasked_list $coll_nuasked_list modeq] mod_to_unload mod_to_load
# proceed as well for modulepath
lassign [getMovementBetweenList $curr_path_list $coll_path_list] \
path_to_unuse path_to_use
# reset implicit_default to restore behavior defined
unsetConf implicit_default
# use paths
if {[llength $path_to_use] > 0} {
# always append path here to guaranty the order
# computed above in the movement lists
cmdModuleUse load append {*}$path_to_use
}
# load modules one by one with user asked state preserved
foreach mod $mod_to_load {
cmdModuleLoad load [expr {$mod ni $coll_nuasked_list}] 0 0\
$coll_tag_arr($mod) $mod
}
popMsgRecordId 0
}
proc cmdModuleSaverm {{coll default}} {
# avoid to remove any kind of file with this command
if {[string first / $coll] > -1} {
reportErrorAndExit {Command does not remove collection specified as\
filepath}
}
# get corresponding collection, raise error if it does not exist, but do
# not check if collection is valid
lassign [findCollections $coll exact 0 1 0] collfile colldesc
# attempt to delete specified collection
if {[catch {
file delete $collfile
} errMsg ]} {
reportErrorAndExit "Collection $colldesc cannot be removed.\n$errMsg"
}
}
proc cmdModuleSaveshow {args} {
# distinguish between zero and one argument provided
if {[llength $args] == 0} {
set arg_provided 0
set coll default
} else {
set arg_provided 1
set coll [lindex $args 0]
}
# get corresponding collection, raise error if it does not exist unless
# if no collection name has been provided or if __init__
lassign [findCollections $coll exact [expr {!$arg_provided}]\
$arg_provided] collfile colldesc
# read specific __init__ collection from __MODULES_LMINIT env var
if {$collfile eq {__init__}} {
lassign [parseCollectionContent [getLoadedModulePropertyList init]]\
coll_path_list coll_mod_list coll_tag_arrser
set collfile {initial environment}
set coll __init__
} else {
lassign [readCollectionContent $collfile $colldesc] coll_path_list\
coll_mod_list coll_tag_arrser
}
# collection should at least define a path or a mod, but initial env may be
# totally empty
if {$coll ne {__init__} && [llength $coll_path_list] == 0 && [llength\
$coll_mod_list] == 0} {
reportErrorAndExit "$colldesc is not a valid collection"
}
displaySeparatorLine
report [sgr hi $collfile]:\n
report [formatCollectionContent $coll_path_list $coll_mod_list\
$coll_tag_arrser {} 1]
displaySeparatorLine
}
proc cmdModuleSavelist {show_oneperline show_mtime search_match args} {
# if a target is set, only list collection matching this target (means
# having target as suffix in their name) unless if --all option is set
set colltarget [getConf collection_target]
if {$colltarget ne {} && [getState hiding_threshold] < 2} {
set suffix .$colltarget
set targetdesc " (for target \"$colltarget\")"
} else {
set suffix {}
set targetdesc {}
}
set json [isStateEqual report_format json]
reportDebug "list collections$targetdesc"
# if only stash collection are expected, start result index at 0, sort
# results in reverse order (latest first) and ensure only collection from
# current target (and no-target if none set) are returned.
if {[getCallingProcName] eq {cmdModuleStashlist}} {
set start_idx 0
set sort_opts [list -dictionary -decreasing]
set find_no_other_target 1
set typedesc stash
# no icase match as stash collections are only lowercases
set icase 0
} else {
set start_idx 1
set sort_opts [list -dictionary]
set find_no_other_target 0
set typedesc named
set icase [isIcase]
}
if {[llength $args] > 0} {
defineModEqProc $icase 0
# match passed name against any part of collection names
set mtest [expr {{contains} in $search_match ? {matchin} : {match}}]
}
# prepare header message which depend if search is performed (no search
# considered if listing stash collections)
if {[llength $args] > 0 && $typedesc ne {stash}} {
set collmsg "Matching $typedesc collection list$targetdesc:"
} else {
set collmsg "[string totitle $typedesc] collection list$targetdesc:"
}
foreach collfile [findCollections * glob 0 0 1 $find_no_other_target] {
# remove target suffix from names to display
regsub $suffix$ [file tail $collfile] {} coll
# filter stash collections unless called by stashlist or --all opt set
if {$typedesc ne {named} || ![regexp {stash-\d+} $coll] || [getState\
hiding_threshold] >= 2} {
set coll_arr($coll) $collfile
}
}
# same header msg if no collection at all whether search is made or not
if {![array exists coll_arr] || $typedesc eq {stash}} {
set nocollmsg "No $typedesc collection$targetdesc."
} else {
set nocollmsg "No matching $typedesc collection$targetdesc."
}
# filter collection not matching any of the passed specification
if {[llength $args] > 0} {
set matchlist [list]
foreach coll [array names coll_arr] {
set match 0
foreach pattern $args {
# compare pattern against collections using comparison module proc
# useful for suffix/prefix/icase checks, disabling module-specific
# checks (variants, alternative names, etc)
if {[modEq $pattern $coll $mtest 0 0 0 0 *]} {
set match 1
break
}
}
if {!$match} {
unset coll_arr($coll)
}
}
}
if {[array size coll_arr] == 0} {
if {!$json} {
report $nocollmsg
}
} else {
if {!$json} {
if {$show_mtime} {
displayTableHeader hi Collection 59 {Last mod.} 19
}
report $collmsg
}
set display_list {}
set len_list {}
set max_len 0
set one_per_line [expr {$show_mtime || $show_oneperline}]
set show_idx [expr {!$one_per_line}]
# prepare query to highlight
set himatchmap [prepareMapToHightlightSubstr {*}$args]
foreach coll [lsort {*}$sort_opts [array names coll_arr]] {
if {$json} {
lappend display_list [formatListEltToJsonDisplay $coll target s\
$colltarget 1 pathname s $coll_arr($coll) 1]
# no need to test coll consistency as findCollections does not return
# collection whose name starts with "."
} else {
set collsgr [sgr {} $coll $himatchmap]
if {$show_mtime} {
set filetime [clock format [getFileMtime $coll_arr($coll)]\
-format {%Y/%m/%d %H:%M:%S}]
lappend display_list [format %-60s%19s $collsgr $filetime]
} else {
lappend display_list $collsgr
lappend len_list [set len [string length $coll]]
if {$len > $max_len} {
set max_len $len
}
}
}
}
displayElementList noheader {} {} $one_per_line $show_idx $start_idx\
$display_list $len_list $max_len
}
}
proc cmdModuleSource {mode args} {
foreach mod $args {
set rawarg [getRawArgumentFromVersSpec $mod]
if {$mod eq {}} {
reportErrorAndExit {File name empty}
# first check if raw specification is an existing file
} elseif {[file exists [set absfpath [getAbsolutePath $rawarg]]]} {
set modfile $absfpath
set modname $absfpath
set modnamevr $absfpath
# unset module specification not to confuse specific char in file
# path (like '+') with variant specification
unsetModuleVersSpec $mod
set mod $absfpath
# if not a path specification, try to resolve a modulefile
} elseif {![isModuleFullPath $rawarg]} {
lassign [getPathToModule $mod] modfile modname modnamevr
# stop if no module found, issue has been reported by getPathToModule
if {$modfile eq {}} {
break
}
} else {
reportErrorAndExit "File $rawarg does not exist"
}
##nagelfar ignore Found constant
lappendState mode $mode
# sourced file must also have a magic cookie set at their start
##nagelfar ignore Suspicious variable name
execute-modulefile $modfile $modname $modnamevr $mod 0 0
##nagelfar ignore Found constant
lpopState mode
}
}
# Intermediate procedure between module and cmdModuleLoad/prereq
# Adapt options and arguments depending on context to call cmdModuleLoad or
# one of the prereq procedures
proc cmdModuleIntLoad {topcall command mode tag_list args} {
# ignore flag used in collection to track non-user asked state
set args [replaceFromList $args --notuasked]
# no error raised on empty argument list to cope with initadd command that
# may expect this behavior
if {[llength $args] == 0} {
return
}
set ret 0
# if top command is source, consider module load commands made within
# sourced file evaluation as top load command
if {[isTopEvaluation]} {
# is eval a regular attempt or a try (silence not found error)
set tryload [expr {$command in {try-load load-any}}]
set loadany [expr {$command eq {load-any}}]
set ret [cmdModuleLoad load 1 $tryload $loadany $tag_list {*}$args]
} elseif {$mode eq {load}} {
# auto load is inhibited if currently in DepRe context only register
# requirement
set subauto [expr {[currentModuleEvalContext] eq {depre} ? {0} : {1}}]
if {$command eq {try-load}} {
# attempt load of not already loaded modules
if {$subauto} {
foreach arg $args {
lassign [loadRequirementModuleList 1 0 $tag_list $arg] retlo
# update return value if an issue occurred unless force mode is
# enabled
if {$retlo != 0 && ![getState force]} {
set ret $retlo
}
}
}
# record requirement as optional: no error if not loaded but reload
# will be triggered if loaded later on
prereqAllModfileCmd 1 0 --optional --tag [join $tag_list :] {*}$args
} elseif {$command eq {load-any}} {
# load and register requirement in a OR-operation
prereqAnyModfileCmd 1 $subauto --tag [join $tag_list :] {*}$args
} else {
# load and register requirement in a AND-operation
prereqAllModfileCmd 0 $subauto --tag [join $tag_list :] {*}$args
}
# mods unload is handled via UReqUn mechanism when auto enabled (unless if
# implicit_requirement has been inhibited) also unloads are triggered by
# ongoing reload, purge, restore, reset, stash or stashpop cmds
} elseif {(![getConf auto_handling] || [getState inhibit_req_record] eq\
[currentState evalid]) && [aboveCommandName] ni [list purge reload\
restore reset stash stashpop]} {
# on unload mode, unload mods in reverse order, if loaded prior this
# mod, if not user asked and not required by other loaded mods
set modlist [getLoadedModulePropertyList name]
set modidx [lsearch -exact $modlist [currentState modulename]]
if {$modidx != 0} {
set priormodlist [lrange $modlist 0 $modidx]
foreach arg [lreverse $args] {
if {[set unmod [getLoadedMatchingName $arg {} 0 $priormodlist]]\
ne {}} {
if {[cmdModuleUnload urequn match 1 0 1 1 $unmod]} {
reportWarning "Unload of useless requirement\
[getModuleDesignation loaded $unmod] failed" 1
}
}
}
}
}
# sub-module interpretation failed, raise error
if {$ret && !$topcall} {
knerror {} MODULES_ERR_SUBFAILED
}
}
proc cmdModuleLoad {context uasked tryload loadany tag_list args} {
reportDebug "loading $args (context=$context, uasked=$uasked,\
tryload=$tryload, loadany=$loadany)"
set ret 0
set loadok 0
lappendState mode load
foreach mod $args {
# stop when first module in list is loaded if any mode enabled
if {$loadok && $loadany} {
break
}
# if a switch action is ongoing...
if {$context eq {swload}} {
set swprocessing 1
# context is ReqLo if switch is called from a modulefile
if {![isMsgRecordIdTop]} {
set context reqlo
}
upvar newhidden hidden
upvar newmsgrecid msgrecid
}
# loading module is visible by default
set hidden 0
# error if module not found or forbidden
set notfounderr [expr {!$tryload}]
# record evaluation attempt on specified module name
registerModuleEvalAttempt $context $mod
lassign [getPathToModule $mod {} $notfounderr] modfile modname modnamevr
# set a unique id to record messages related to this evaluation.
set msgrecid load-$modnamevr-[depthState modulename]
# go to next module to load if not matching module found
if {$modfile eq {}} {
set ret $notfounderr
continue
}
if {[isModuleEvalFailed load $modnamevr]} {
reportDebug "$modnamevr ($modfile) load was already tried and failed"
# nullify this evaluation attempt to avoid duplicate issue report
unregisterModuleEvalAttempt $context $mod
continue
}
# if a switch action is ongoing...
if {[info exists swprocessing]} {
# pass the DepRe mod list to the calling cmdModuleSwitch procedure to
# let it handle the load phase of the DepRe mechanism along with the
# DepRe modules set from switched off module.
upvar deprelist swdeprelist
upvar depreisuasked depreisuasked
upvar deprevr deprevr
upvar depreextratag depreextratag
# transmit loaded mod name for switch report summary
uplevel 1 set new "{$modnamevr}"
}
# register record message unique id (now we know mod will be evaluated)
pushMsgRecordId $msgrecid
# record evaluation attempt on actual module name
registerModuleEvalAttempt $context $modnamevr
registerModuleEvalAttempt $context $modfile
# check if passed modname correspond to an already loaded modfile
# and get its loaded name (in case it has been loaded as full path)
set loadedmodname [getLoadedMatchingName $modnamevr]
if {$loadedmodname ne {}} {
set modname $loadedmodname
set modnamevr $modname
if {[set vr [getVariantList $modname 1]] ne {}} {
append modnamevr " $vr"
}
}
# record module title (with the variant specified on load call, and no
# tag list) prior module evaluation to get this title ready in case of
# eval error
registerModuleDesignation $msgrecid $modname [getVariantList $mod 7 0\
1] {}
pushSettings
if {[set errCode [catch {
if {[set isloaded [isModuleLoaded $modname]] || [set isloading\
[isModuleLoading $modname]]} {
reportDebug "$modname ($modfile) already loaded/loading"
# stop if same mod is loaded but with a different set of variants
if {$modname ne $modnamevr && (($isloaded &&
[getLoadedMatchingName $modnamevr] eq {}) || ([info exists\
isloading] && $isloading && [getLoadedMatchingName $modnamevr\
{} 1] eq {}))} {
set errlocalreport 1
knerror [getModWithAltVrIsLoadedMsg $modname]
} else {
# apply missing tag to loaded module
set rettag [cmdModuleTag 0 $uasked $tag_list $modname]
# report module is already loaded if verbose2 or higher level
# and no new tag set
if {$isloaded && $rettag != 2 && [isVerbosityLevel verbose2]} {
reportInfo "Module '$modname' is already loaded"
registerModuleDesignation $msgrecid $modname\
[getVariantList $modname 7] [getExportTagList $modname]
reportMsgRecord "Loading [getModuleDesignation $msgrecid {}\
2]"
}
# exit treatment but no need to restore settings
set loadok 1
continue
}
}
# register altname of modname prior any conflict check
setLoadedAltname $modname {*}[getAllModuleResolvedName $modname 1\
$mod]
if {[getConf auto_handling]} {
# get loaded modules holding a requirement on modname and able to
# be reloaded
set deprelist [getUnmetDependentLoadedModuleList $modnamevr]
reportDebug "depre mod list is '$deprelist'"
# Reload all modules that have declared a prereq on mod as they
# may take benefit from their prereq availability if it is newly
# loaded. First perform unload phase of the reload, prior mod load
# to ensure these dependent modules are unloaded with the same
# loaded prereq as when they were loaded
if {[llength $deprelist] > 0} {
lassign [reloadModuleListUnloadPhase deprelist [getState\
force] {Unload of dependent _MOD_ failed} depun]\
depreisuasked deprevr depreextratag
if {[info exists swprocessing]} {
if {[info exists swdeprelist]} {
set swdeprelist [list {*}$deprelist {*}$swdeprelist]
} else {
set swdeprelist $deprelist
}
}
}
}
# record additional tags passed through --tag option prior mod eval
# to make them known within evaluation
if {[llength $tag_list] > 0} {
# record tags set with --tag as extra tag excluding tags relative
# to the way module is loaded (auto, keep)
lassign [getDiffBetweenList $tag_list [list auto-loaded\
keep-loaded]] extratag_list
setModuleTag $modname {*}$tag_list
if {[llength $extratag_list] > 0} {
setModuleExtraTag $modname {*}$extratag_list
}
if {$modnamevr ne {} && $modname ne $modnamevr} {
setModuleTag $modnamevr {*}$tag_list
if {[llength $extratag_list] > 0} {
setModuleExtraTag $modnamevr {*}$extratag_list
}
}
}
if {[execute-modulefile $modfile $modname modnamevr $mod]} {
break
}
# register this evaluation on the main one that triggered it (after
# load evaluation to report correct order with other evaluations)
registerModuleEval $context $msgrecid
# raise an error if a conflict violation is detected
# do that after modfile evaluation to give it the chance to solve its
# (module unload) conflicts through its evaluation
lassign [doesModuleConflict $modname] doescon modconlist\
moddecconlist
set retisconun [isModuleEvaluated conun $modnamevr {*}$modconlist]
if {![set retiseval [isModuleEvaluated any $modnamevr\
{*}$modconlist]] || [currentState msgrecordid] ne [topState\
msgrecordid] || !$retisconun} {
# more appropriate msg if an evaluation was attempted or is
# by-passed. error is reported using declared conflict name (as if
# it was raised raised from a conflict modulefile command)
set conmsg [expr {$retiseval || [getState force] ?\
[getConIsLoadedMsg $moddecconlist [is-loading $modconlist]] :\
[getErrConflictMsg $moddecconlist]}]
}
# still proceed if force mode enabled
if {[getState force] && $doescon} {
defineModEqProc [isIcase] [getConf extended_default]
# report warning if not already done
set report_con 1
if {[info exists ::report_conflict($msgrecid)]} {
# check if conflict has not been already reported with an
# alternative name
foreach modcon $modconlist {
foreach reportmod $::report_conflict($msgrecid) {
if {[modEq $reportmod $modcon eqstart 1 2 1]} {
set report_con 0
break
}
}
if {!$report_con} {
break
}
}
if {$report_con} {
foreach moddeccon $moddecconlist {
foreach reportmod $::report_conflict($msgrecid) {
if {[modEq $reportmod $moddeccon eqstart]} {
set report_con 0
break
}
}
if {!$report_con} {
break
}
}
}
}
if {$report_con && [info exists conmsg]} {
reportWarning $conmsg
}
# raise conun-specific msg to top level if attempted
if {$retisconun} {
reportWarning [getErrConUnMsg $moddecconlist] 1
}
} elseif {$doescon} {
if {$retisconun} {
if {[info exists conmsg]} {
reportError $conmsg
}
# raise conun-specific msg to top level if attempted
knerror [getErrConUnMsg $moddecconlist]
} else {
set errlocalreport 1
knerror $conmsg
}
}
# loading visibility depends on hidden-loaded tag
set hidden [isModuleTagged $modnamevr hidden-loaded 1 $modfile]
append-path LOADEDMODULES $modname
# allow duplicate modfile entries for virtual modules
append-path --duplicates _LMFILES_ $modfile
# update cache arrays
setLoadedModule $modname $modfile $uasked $modnamevr [expr {$modname\
in [getState refresh_qualified]}]
# register declared source-sh in environment
if {[set modsrcsh [getLoadedSourceSh $modname 1]] ne {}} {
append-path __MODULES_LMSOURCESH $modsrcsh
}
# register declared conflict in environment
if {[set modcon [getLoadedConflict $modname 1]] ne {}} {
append-path __MODULES_LMCONFLICT $modcon
}
# declare the prereq of this module
if {[set modpre [getLoadedPrereq $modname 1]] ne {}} {
append-path __MODULES_LMPREREQ $modpre
}
# declare the alternative names of this module
if {[set modalt [getLoadedAltname $modname 1]] ne {}} {
append-path __MODULES_LMALTNAME $modalt
}
# declare the variant of this module
if {[set modvrspec [getLoadedVariant $modname 1]] ne {}} {
append-path __MODULES_LMVARIANT $modvrspec
}
# declare the tags of this module
if {[set modtag [getExportTagList $modnamevr 1 $modfile]] ne {}} {
append-path __MODULES_LMTAG $modtag
}
if {[set modtag [getExtraTagList $modnamevr 1]] ne {}} {
append-path __MODULES_LMEXTRATAG $modtag
}
# declare module qualified for refresh evaluation
if {[isModuleRefreshQualified $modname]} {
append-path __MODULES_LMREFRESH $modname
}
# Load phase of dependent module reloading. These modules can adapt
# now that mod is seen loaded. Except if switch action ongoing (DepRe
# load phase will occur from switch)
if {[getConf auto_handling] && [llength $deprelist] > 0 && ![info\
exists swprocessing]} {
reloadModuleListLoadPhase deprelist $depreisuasked $deprevr\
$depreextratag [getState force] {Reload of dependent _MOD_\
failed} depre
}
# record module title (name, variants and tags)
registerModuleDesignation $msgrecid $modname [getVariantList\
$modname 7] [getExportTagList $modname 0 $modfile]
# consider evaluation hidden if hidden loaded module is auto loaded
# and no specific messages are recorded for this evaluation
if {$hidden && !$uasked && ![isMsgRecorded]} {
registerModuleEvalHidden $context $msgrecid
}
# report a summary of automated evaluations if no error
reportModuleEval
} errMsg]] != 0 && $errCode != 4} {
# in case of error report module info even if set hidden
set hidden 0
if {$errMsg ne {}} {
reportError $errMsg [expr {![info exists errlocalreport]}]
}
# report switched-on module load failure under switch info block
# unless the above reportError call already put a mesg to this block
if {[info exists swprocessing] && ($errMsg eq {} || [info exists\
errlocalreport])} {
# warn as this issue does not lead to a rollback of switch action
reportWarning "Load of switched-on [getModuleDesignation\
$msgrecid] failed" 1
}
# rollback settings if some evaluation went wrong
set ret 1
restoreSettings
# remove from successfully evaluated module list
registerModuleEval $context $msgrecid $modnamevr load
unset -nocomplain errlocalreport
}
popSettings
# report all recorded messages for this evaluation except if module were
# already loaded
if {$errCode != 4} {
reportMsgRecord "Loading [getModuleDesignation $msgrecid {} 2]"\
[expr {$hidden && !$uasked}]
}
popMsgRecordId
if {$errCode == 0} {
set loadok 1
}
}
lpopState mode
# raise error if no module has been loaded or has produced an error during
# its load attempt in case of top-level load-any sub-command
if {!$ret && !$loadok && $context eq {load} && $loadany} {
knerror "No module has been loaded"
}
return $ret
}
# Intermediate procedure between module and cmdModuleUnload
# Adapt options and arguments depending on context to call cmdModuleUnload
proc cmdModuleIntUnload {mode args} {
# if top command is source, consider module load commands made within
# sourced file evaluation as top load command
if {[isTopEvaluation]} {
set ret [cmdModuleUnload unload match 1 0 0 0 {*}$args]
} elseif {$mode eq {load}} {
# unload mods only on load mode, nothing done on unload mode as the
# registered conflict guarantees the target module cannot be loaded
# unless forced
# do not unload module required by others even in force mode
set ret [cmdModuleUnload conun match 0 0 0 1 {*}$args]
# register modulefiles to unload as individual conflicts
foreach arg $args {
# do not break on error yet, go through the whole modfile evaluation
# in case conflict is solved later on
catch {conflict $arg}
}
# sub-module interpretation failed, raise error
if {$ret} {
knerror {} MODULES_ERR_SUBFAILED
}
}
}
proc cmdModuleUnload {context match auto force onlyureq onlyndep args} {
reportDebug "unloading $args (context=$context, match=$match, auto=$auto,\
force=$force, onlyureq=$onlyureq, onlyndep=$onlyndep)"
set ret 0
lappendState mode unload
foreach mod $args {
# if a switch action is ongoing...
if {$context eq {swunload}} {
set swprocessing 1
# context is ConUn if switch is called from a modulefile
if {![isMsgRecordIdTop]} {
set context conun
}
upvar oldhidden hidden
upvar olduasked uasked
upvar oldmsgrecid msgrecid
}
# unloading module is visible by default
set hidden 0
set uasked 1
# record evaluation attempt on specified module name
registerModuleEvalAttempt $context $mod
# resolve by also looking at matching loaded module and update mod
# specification to fully match obtained loaded module
# enable report_issue flag to report empty module name issue
lassign [getPathToModule $mod {} 1 $match] modfile modname\
modnamevr errkind
# set a unique id to record messages related to this evaluation.
set msgrecid unload-$modnamevr-[depthState modulename]
# record module title (with the variant specified on unload call, and no
# tag list) prior module evaluation to get this title ready in case of
# eval error
registerModuleDesignation $msgrecid $modname [getVariantList $modnamevr\
7 0 1] {}
# if a switch action is ongoing...
if {[info exists swprocessing]} {
# pass the DepRe mod list to the calling cmdModuleSwitch
# procedure to let it handle the load phase of the DepRe
# mechanism once the switched-to module will be loaded
upvar deprelist deprelist
upvar depreisuasked depreisuasked
upvar deprevr deprevr
upvar depreextratag depreextratag
# transmit unloaded mod name for switch report summary
uplevel 1 set old "{$modnamevr}"
}
if {$modfile eq {}} {
# no error return if module is not loaded
if {$errkind eq {notloaded}} {
reportDebug "$modname is not loaded"
# report module is not loaded if verbose2 or higher level
if {[isVerbosityLevel verbose2]} {
pushMsgRecordId $msgrecid
reportInfo "Module '$modname' is not loaded"
reportMsgRecord "Unloading [getModuleDesignation $msgrecid {}\
2]"
}
} else {
# return error code in case of empty module name
set ret 1
}
# go to next module to unload
continue
}
if {$onlyureq && ![isModuleUnloadable $modname]} {
reportDebug "$modname ($modfile) is required by loaded module or\
asked by user"
continue
}
if {[isModuleEvalFailed unload $modnamevr]} {
reportDebug "$modnamevr ($modfile) unload was already tried and\
failed"
# nullify this evaluation attempt to avoid duplicate issue report
unregisterModuleEvalAttempt $context $mod
continue
}
# register record message unique id (now we know mod will be evaluated)
pushMsgRecordId $msgrecid
# record evaluation attempt on actual module name
registerModuleEvalAttempt $context $modnamevr
registerModuleEvalAttempt $context $modfile
# record module title (name, variants and tags)
registerModuleDesignation $msgrecid $modname [getVariantList $modname\
7] [getExportTagList $modname]
pushSettings
if {[set errCode [catch {
# error if unloading module violates a registered prereq
# and auto handling mode is disabled
set prereq_list [getDependentLoadedModuleList [list $modname]]
if {[llength $prereq_list] > 0 && (![getConf auto_handling] ||\
!$auto)} {
# force mode should not affect if we only look for mods w/o dep
##nagelfar ignore Found constant
if {([getState force] || $force) && !$onlyndep} {
# in case unload is called for a DepRe mechanism do not warn
# about prereq violation enforced as it is due to the dependent
# module which is already in a violation state
# warn in case of a purge
if {$auto || !$force || [currentState commandname] eq\
{purge}} {
reportWarning [getDepLoadedMsg $prereq_list]
}
} else {
set errlocalreport 1
# exit treatment but no need to set return code to error if
# called from a 'module unload' command in a modulefile in a
# load evaluation mode, as set conflict will raise error at end
# of modulefile evaluation
if {$onlyndep} {
set errharmless 1
}
knerror [expr {[isModuleEvaluated any $modnamevr\
{*}$prereq_list] ? [getDepLoadedMsg $prereq_list] :\
[getErrPrereqMsg $prereq_list 0]}]
}
}
if {[getConf auto_handling] && $auto} {
# compute lists of modules to update due to modname unload prior
# unload to get requirement info before it vanishes
# DepUn: Dependent to Unload (modules actively requiring modname
# or a module part of this DepUn batch)
set depunnpolist [getDependentLoadedModuleList [list $modname] 1\
0 1 0]
set depunlist [getDependentLoadedModuleList [list $modname] 1 0 0\
0]
# look at both regular dependencies or No Particular Order
# dependencies: use NPO result if situation can be healed with NPO
# dependencies, which will be part of DepRe list to restore the
# correct loading order for them
if {[llength $depunnpolist] <= [llength $depunlist]} {
set depunlist $depunnpolist
}
reportDebug "depun mod list is '$depunlist'"
# do not check for UReqUn mods coming from DepUn modules as these
# DepUn modules are reloaded
if {[info exists swprocessing]} {
set urequnqry [list $modname]
} else {
set urequnqry [list {*}$depunlist $modname]
}
# UReqUn: Useless Requirement to Unload (autoloaded requirements
# of modname or DepUn modules not required by any remaining mods)
set urequnlist [getUnloadableLoadedModuleList $urequnqry]
reportDebug "urequn mod list is '$urequnlist'"
# DepRe: Dependent to Reload (modules optionally dependent or in
# conflict with modname, DepUn or UReqUn modules + modules
# dependent of a module part of this DepRe batch)
set deprelist [getDependentLoadedModuleList [list {*}$urequnlist\
{*}$depunlist $modname] 0 0 1 0 1 1]
reportDebug "depre mod list is '$deprelist'"
# DepUn mods are merged into the DepRe list as an attempt to
# reload these DepUn mods is made once switched-to mod loaded
if {[info exists swprocessing]} {
set deprelist [sortModulePerLoadedAndDepOrder [list\
{*}$depunlist {*}$deprelist] 1]
set depunlist {}
}
# Reload of all DepRe mods, as they may adapt from the mod unloads
# happening here. First perform unload phase of the reload, prior
# mod unloads to ensure these dependent mods are unloaded with the
# same loaded prereq as when they were loaded. Avoid modules not
# satisfying their constraint.
if {[llength $deprelist] > 0} {
##nagelfar ignore +2 Found constant
lassign [reloadModuleListUnloadPhase deprelist [getState\
force] {Unload of dependent _MOD_ failed} depun]\
depreisuasked deprevr depreextratag
}
# DepUn modules unload prior main mod unload
if {[llength $depunlist] > 0} {
foreach unmod [lreverse $depunlist] {
##nagelfar ignore Found constant
if {[cmdModuleUnload depun match 0 0 0 0 $unmod]} {
# stop if one unload fails unless force mode enabled
set errMsg "Unload of dependent [getModuleDesignation\
loaded $unmod] failed"
##nagelfar ignore Found constant
if {[getState force] || $force} {
reportWarning $errMsg 1
} else {
knerror $errMsg
}
}
}
}
}
# register this evaluation on the main one that triggered it (prior
# unload evaluation to report correct order with other evaluations)
registerModuleEval $context $msgrecid
# no need to update modnamevr and tags after evaluation as these
# information were already complete in persistent environment
##nagelfar ignore Suspicious variable name
if {[execute-modulefile $modfile $modname $modnamevr $mod 0 0]} {
break
}
# unloading visibility depends on hidden-loaded tag
set hidden [isModuleTagged $modname hidden-loaded 1]
# module was asked by user if tagged loaded instead of auto-loaded
set uasked [isModuleTagged $modname loaded 1]
# unset module from list of loaded modules qualified for refresh eval
if {[isModuleRefreshQualified $modname]} {
remove-path __MODULES_LMREFRESH $modname
}
# get module position in loaded list to remove corresponding loaded
# modulefile (entry at same position in _LMFILES_)
# need the unfiltered loaded module list to get correct index
set lmidx [lsearch -exact [getLoadedModulePropertyList name 0]\
$modname]
remove-path LOADEDMODULES $modname
remove-path --index _LMFILES_ $lmidx
# update cache arrays
unsetLoadedModule $modname $modfile
# unregister declared source-sh
if {[set modsrcsh [getLoadedSourceSh $modname 1]] ne {}} {
remove-path __MODULES_LMSOURCESH $modsrcsh
}
unsetLoadedSourceSh $modname
# unregister declared conflict
if {[set modcon [getLoadedConflict $modname 1]] ne {}} {
remove-path __MODULES_LMCONFLICT $modcon
}
unsetLoadedConflict $modname
# unset prereq declared for this module
if {[llength [set modpre [getLoadedPrereq $modname]]] > 0} {
remove-path __MODULES_LMPREREQ [getLoadedPrereq $modname 1]
}
unsetLoadedPrereq $modname
# unset alternative names declared for this module
if {[llength [set modalt [getLoadedAltname $modname]]] >0} {
remove-path __MODULES_LMALTNAME [getLoadedAltname $modname 1]
}
unsetLoadedAltname $modname
# unset variant declared for this module
if {[llength [set modvrspec [getLoadedVariant $modname]]] > 0} {
remove-path __MODULES_LMVARIANT [getLoadedVariant $modname 1]
}
unsetLoadedVariant $modname
# unset tags declared for this module
if {[set modtag [getExportTagList $modname 1]] ne {}} {
remove-path __MODULES_LMTAG $modtag
# also remove the auto-loaded and keep-loaded tags from
# in-memory knowledge not to re-apply them if module is reloaded
# in other conditions
unsetModuleTag $modname auto-loaded keep-loaded
if {$modnamevr ne {} && $modname ne $modnamevr} {
unsetModuleTag $modnamevr auto-loaded keep-loaded
}
}
if {[set modtag [getExtraTagList $modname 1]] ne {}} {
remove-path __MODULES_LMEXTRATAG $modtag
# also remove extra tags from in-memory knowledge not re-apply
# them if module is reloaded in other conditions
set extratag_list [getExtraTagList $modname]
unsetModuleTag $modname {*}$extratag_list
unsetModuleExtraTag $modname {*}$extratag_list
if {$modnamevr ne {} && $modname ne $modnamevr} {
unsetModuleTag $modnamevr {*}$extratag_list
unsetModuleExtraTag $modnamevr {*}$extratag_list
}
}
if {[getConf auto_handling] && $auto} {
# UReqUn modules unload now DepUn+main mods are unloaded
if {[llength $urequnlist] > 0} {
set urequnlist [lreverse $urequnlist]
for {set i 0} {$i < [llength $urequnlist]} {incr i 1} {
set unmod [lindex $urequnlist $i]
##nagelfar ignore Found constant
if {[cmdModuleUnload urequn match 0 0 0 0 $unmod]} {
# just warn if UReqUn module cannot be unloaded, main
# unload process continues, just the UReqUn modules that
# are required by unmod (whose unload failed) are
# withdrawn from UReqUn module list
reportWarning "Unload of useless requirement\
[getModuleDesignation loaded $unmod] failed" 1
lassign [getDiffBetweenList $urequnlist\
[getRequiredLoadedModuleList [list $unmod]]]\
urequnlist
}
}
}
# DepRe modules load phase now DepUn+UReqUn+main mods are unloaded
# except if a switch action is ongoing as this DepRe load phase
# will occur after the new mod load
if {[llength $deprelist] > 0 && ![info exists swprocessing]} {
##nagelfar ignore +2 Found constant
reloadModuleListLoadPhase deprelist $depreisuasked $deprevr\
$depreextratag [getState force] {Reload of dependent _MOD_\
failed} depre
}
}
# consider evaluation hidden if hidden loaded module was auto loaded
# and no specific messages are recorded for this evaluation
if {$hidden && !$uasked && ![isMsgRecorded]} {
registerModuleEvalHidden $context $msgrecid
}
# report a summary of automated evaluations if no error
reportModuleEval
} errMsg]] != 0 && $errCode != 4} {
# in case of error report module info even if set hidden
set hidden 0
if {$errMsg ne {}} {
reportError $errMsg [expr {![info exists errlocalreport]}]
}
# report switched-off module unload failure under switch info block
# unless the above reportError call already put a mesg to this block
if {[info exists swprocessing] && ($errMsg eq {} || [info exists\
errlocalreport])} {
reportError "Unload of switched-off [getModuleDesignation loaded\
$modname] failed" 1
}
# rollback settings if some evaluation went wrong
if {![info exists errharmless]} {
set ret 1
restoreSettings
# remove from successfully evaluated module list
registerModuleEval $context $msgrecid $modnamevr unload
}
unset -nocomplain errlocalreport errharmless
}
popSettings
# report all recorded messages for this evaluation (hide evaluation if
# loaded mod is set hidden, has been automatically loaded and unloaded)
reportMsgRecord "Unloading [getModuleDesignation $msgrecid {} 2]" [expr\
{$hidden && !$uasked && [depthState evalid] != 1}]
popMsgRecordId
}
lpopState mode
return $ret
}
proc cmdModulePurge {} {
# create an eval id to track successful/failed module evaluations
pushMsgRecordId purge-[depthState modulename] 0
# unload one by one to ensure same behavior whatever auto_handling state
# force it to handle loaded modules in violation state
# remove dependent modules if force mode enabled
set onlyndep [expr {![getState force]}]
cmdModuleUnload unload match 0 1 0 $onlyndep {*}[lreverse\
[getLoadedModulePropertyList name]]
popMsgRecordId 0
}
proc cmdModuleReload {args} {
# reload all loaded modules if no module list passed
if {[llength $args] == 0} {
set lmlist [getLoadedModulePropertyList name]
} else {
set lmlist $args
}
reportDebug "reloading $lmlist"
# create an eval id to track successful/failed module evaluations
pushMsgRecordId reload-[depthState modulename] 0
# no reload of all loaded modules attempt if constraints are violated
if {[llength $args] == 0 && ![areModuleConstraintsSatisfied]} {
reportError {Cannot reload modules, some of their constraints are not\
satistied}
} else {
pushSettings
if {[set errCode [catch {
# run unload then load-again phases
lassign [reloadModuleListUnloadPhase lmlist] isuasked vr extratag
reloadModuleListLoadPhase lmlist $isuasked $vr $extratag
} errMsg]] == 1} {
# rollback settings if some evaluation went wrong
restoreSettings
}
popSettings
}
popMsgRecordId 0
}
proc cmdModuleAliases {} {
# disable error reporting to avoid modulefile errors
# to mix with avail results
inhibitErrorReport
# parse paths to fill g_moduleAlias and g_moduleVersion
foreach dir [getModulePathList exiterronundef] {
getModules $dir {} 0 {}
}
setState inhibit_errreport 0
set display_list {}
foreach name [lsort -dictionary [array names ::g_moduleAlias]] {
# exclude hidden aliases from result
if {![isModuleHidden $name]} {
lappend display_list "[sgr al $name] -> $::g_moduleAlias($name)"
}
}
displayElementList Aliases hi sepline 1 0 0 $display_list
set display_list {}
foreach name [lsort -dictionary [array names ::g_moduleVersion]] {
# exclude hidden versions or versions targeting an hidden module
if {![isModuleHidden $name] && ![isModuleHidden\
$::g_moduleVersion($name)]} {
lappend display_list "[sgr sy $name] -> $::g_moduleVersion($name)"
}
}
displayElementList Versions hi sepline 1 0 0 $display_list
}
proc cmdModuleAvail {show_oneperline show_mtime show_filter search_filter\
search_match args} {
if {[llength $args] == 0} {
lappend args *
}
if {$show_mtime || $show_oneperline} {
set one_per_line 1
set hstyle terse
set theader_cols [list hi Package/Alias 39 Versions 19 {Last mod.} 19]
} else {
set one_per_line 0
set hstyle sepline
set theader_cols {}
}
# set a default filter (do not print dirs with no sym) if none set
if {$show_filter eq {}} {
set show_filter noplaindir
}
# elements to include in output
set report_modulepath [isEltInReport modulepath]
# consolidate search filters
lappend search_filter $search_match wild
set search_rc_filter $search_filter
lappend search_rc_filter rc_alias_only
# disable error reporting to avoid modulefile errors
# to mix with avail results
inhibitErrorReport
foreach mod $args {
set search_queries [list $mod]
array unset mod_list
# look if aliases have been defined in the global or user-specific
# modulerc and display them if any in a dedicated list
array set mod_list [getModules {} $mod $show_mtime $search_rc_filter\
$show_filter]
if {$report_modulepath} {
reportModules $search_queries {global/user modulerc} hi $hstyle\
$show_mtime 0 $one_per_line $theader_cols hidden-loaded
}
foreach dir [getModulePathList exiterronundef] {
if {$report_modulepath} {
array unset mod_list
# get module list (process full dir content and do not exit when
# err is raised from a modulerc)
array set mod_list [getModules $dir $mod $show_mtime\
$search_filter $show_filter]
set modpath_label [getModulepathLabel $dir]
reportModules $search_queries $modpath_label mp $hstyle\
$show_mtime 0 $one_per_line $theader_cols hidden-loaded
} else {
# add result if not already added from an upper priority modpath
foreach {elt props} [getModules $dir $mod $show_mtime\
$search_filter $show_filter] {
if {![info exists mod_list($elt)]} {
set mod_list($elt) $props
}
}
}
}
# no report by modulepath, mix all aggregated results
if {!$report_modulepath} {
reportModules $search_queries noheader {} {} $show_mtime 0\
$one_per_line $theader_cols hidden-loaded
}
}
# display output key
if {!$show_mtime && ![isStateEqual report_format json] && [isEltInReport\
key]} {
displayKey
}
setState inhibit_errreport 0
}
proc runModuleUse {cmd mode pos args} {
if {$args eq {}} {
showModulePath
} else {
if {$pos eq {remove}} {
# get current module path list
set modpathlist [getModulePathList returnempty 0 0]
}
foreach path $args {
switch -glob -- $path {
--remove-on-unload - --append-on-unload - --prepend-on-unload -\
--noop-on-unload {
if {$cmd ne {unuse}} {
knerror "Invalid option '$path'"
} else {
lappend pathlist $path
}
}
-* {
knerror "Invalid option '$path'"
}
{} {
reportError [getEmptyNameMsg directory]
}
$* {
lappend pathlist $path
}
default {
if {$pos eq {remove}} {
if {$path in $modpathlist} {
lappend pathlist $path
# transform given path in an absolute path which should have
# been registered in the MODULEPATH env var. however for
# compatibility with previous behavior where relative paths
# were registered in MODULEPATH given path is first checked
# against current path list
} elseif {[set abspath [getAbsolutePath $path]] in\
$modpathlist} {
lappend pathlist $abspath
# even if not found, transmit this path to remove-path in
# case several path elements have been joined as one string
} else {
lappend pathlist $path
}
} else {
# transform given path in an absolute path to avoid
# dependency to the current work directory. except if this
# path starts with a variable reference
lappend pathlist [getAbsolutePath $path]
}
}
}
}
# added directory may not exist at this time
# pass all paths specified at once to append-path/prepend-path
if {[info exists pathlist]} {
set optlist [list]
# define path command to call
set pathcmd [expr {$pos eq {remove} ? {unload-path} : {add-path}}]
# by-pass any reference counter in case use is called from top level
# not to increase reference counter if paths are already defined
if {[isTopEvaluation]} {
lappend optlist --ignore-refcount
}
if {[isTopEvaluation]} {
##nagelfar ignore Found constant
lappendState mode load
}
$pathcmd $pos-path $mode $pos {*}$optlist MODULEPATH {*}$pathlist
if {[isTopEvaluation]} {
##nagelfar ignore Found constant
lpopState mode
}
}
}
}
proc cmdModuleUse {mode pos args} {
if {$mode eq {unload}} {
set pos remove
}
runModuleUse use $mode $pos {*}$args
}
proc cmdModuleUnuse {mode args} {
runModuleUse unuse $mode remove {*}$args
}
proc cmdModuleAutoinit {} {
# skip autoinit process if found already ongoing in current environment
if {[get-env __MODULES_AUTOINIT_INPROGRESS] eq {1}} {
return
}
# set environment variable to state autoinit process is ongoing
setenv __MODULES_AUTOINIT_INPROGRESS 1
# flag to make renderSettings define the module command
setState autoinit 1
# initialize env variables around module command
lappendState mode load
# register command location
setenv MODULES_CMD [getAbsolutePath $::argv0]
# define current Modules version if versioning enabled
@VERSIONING@if {![info exists ::env(MODULE_VERSION)]} {
@VERSIONING@ setenv MODULE_VERSION @MODULES_RELEASE@@MODULES_BUILD@
@VERSIONING@ setenv MODULE_VERSION_STACK @MODULES_RELEASE@@MODULES_BUILD@
@VERSIONING@}
# initialize MODULEPATH and LOADEDMODULES if found unset
if {![info exists ::env(MODULEPATH)]} {
setenv MODULEPATH {}
}
if {![info exists ::env(LOADEDMODULES)]} {
setenv LOADEDMODULES {}
}
# initialize user environment if found undefined (both MODULEPATH and
# LOADEDMODULES empty)
if {[get-env MODULEPATH] eq {} && [get-env LOADEDMODULES] eq {}} {
# set modpaths defined in modulespath config file if it exists
# use .modulespath file in initdir if conf file are located in this dir
if {[file readable {@modulespath@}]} {
set fdata [split [readFile {@modulespath@}] \n]
foreach fline $fdata {
if {[regexp {^\s*(.*?)\s*(#.*|)$} $fline match patharg] == 1\
&& $patharg ne {}} {
foreach path [split $patharg :] {
# resolve path directory in case wildcard character used
set globlist [glob -types d -nocomplain $path]
if {[llength $globlist] == 0} {
lappend pathlist $path
} else {
lappend pathlist {*}$globlist
}
}
}
}
if {[info exists pathlist]} {
cmdModuleUse load append {*}$pathlist
}
}
# source initialization initrc after modulespaths if it exists
# use modulerc file in initdir if conf files are located in this dir
if {[file exists {@initrc@}]} {
lappendState commandname source
cmdModuleSource load {@initrc@}
lpopState commandname
}
# record what has just been loaded in the virtual init collection
setenv __MODULES_LMINIT [getLoadedInit]
# if user environment is already initialized, refresh the already loaded
# modules unless if environment is inconsistent
} elseif {![catch {cacheCurrentModules}]} {
cmdModuleRefresh
}
# default MODULESHOME
setenv MODULESHOME [getConf home]
# append dir where to find module function for ksh (to get it defined in
# interactive and non-interactive sub-shells). also applies for shells
# listed in shells_with_ksh_fpath conf
if {[getState shell] in [list {*}[split [getConf shells_with_ksh_fpath] :]\
ksh]} {
append-path FPATH {@initdir@/ksh-functions}
}
# define Modules init script as shell startup file
if {[getConf set_shell_startup] && [getState shelltype] in [list sh csh\
fish]} {
# setup ENV variables to get module defined in sub-shells (works for
# 'sh' and 'ksh' in interactive mode and 'sh' (zsh-compat), 'bash' and
# 'ksh' (zsh-compat) in non-interactive mode.
setenv ENV {@initdir@/profile.sh}
setenv BASH_ENV {@initdir@/bash}
}
if {[getState shelltype] in {sh csh fish}} {
# add Modules bin directory to PATH if enabled but do not increase ref
# counter variable if already there
@setbinpath@if {{@bindir@} ni [split [get-env PATH] :]} {
@setbinpath@@appendbinpath@-path --ignore-refcount PATH {@bindir@}
@setbinpath@}
# add Modules man directory to MANPATH if enabled
# initialize MANPATH if not set with a value that preserves manpath
# system configuration even after addition of paths to this variable by
# modulefiles
@setmanpath@set manpath {}
# use manpath tool if found at configure step, use MANPATH otherwise
##nagelfar ignore +2 Too long line
##nagelfar ignore Found constant
@setmanpath@@usemanpath@catch {set manpath [exec -ignorestderr 2>/dev/null manpath]}
@setmanpath@@notusemanpath@if {[info exists ::env(MANPATH)]} {
@setmanpath@@notusemanpath@ set manpath $::env(MANPATH)
@setmanpath@@notusemanpath@}
@setmanpath@if {{@mandir@} ni [split $manpath :]} {
@setmanpath@ if {![info exists ::env(MANPATH)]} {
@setmanpath@ append-path MANPATH {}
@setmanpath@ # ensure no duplicate ':' is set
@setmanpath@ } elseif {[get-env MANPATH] eq {:}} {
@setmanpath@ remove-path MANPATH {}
@setmanpath@ append-path MANPATH {}
@setmanpath@ }
@setmanpath@ @appendmanpath@-path MANPATH {@mandir@}
@setmanpath@}
}
# source shell completion script if available, not installed in default
# completion locations and only if shell is interactive
if {[getState shell] in {@shellcompsource@} && [getState is_stderr_tty]} {
set compfile "@initdir@/[getState shell]_completion"
if {[file readable $compfile]} {
putsModfileCmd dummy "source '$compfile';"
}
}
# clear in progress flag
unsetenv __MODULES_AUTOINIT_INPROGRESS
lpopState mode
}
proc cmdModuleInit {args} {
set init_cmd [lindex $args 0]
set init_list [lrange $args 1 end]
set notdone 1
set nomatch 1
# Define startup files for each shell
set files(csh) [list .modules .cshrc .cshrc_variables .login]
set files(tcsh) [list .modules .tcshrc .cshrc .cshrc_variables .login]
set files(sh) [list .modules .bash_profile .bash_login .profile .bashrc]
set files(bash) $files(sh)
set files(ksh) $files(sh)
set files(fish) [list .modules .config/fish/config.fish]
set files(zsh) [list .modules .zshrc .zshenv .zlogin]
# Process startup files for this shell
set current_files $files([getState shell])
foreach filename $current_files {
if {$notdone} {
set filepath $::env(HOME)
append filepath / $filename
reportDebug "Looking at $filepath"
if {[file readable $filepath] && [file isfile $filepath]} {
set newinit {}
set thismatch 0
foreach curline [split [readFile $filepath] \n] {
# Find module load/add command in startup file
set comments {}
if {$notdone && [regexp {^([ \t]*module[ \t]+(load|add)[\
\t]*)(.*)} $curline match cmd subcmd modules]} {
set nomatch 0
set thismatch 1
regexp {([ \t]*\#.+)} $modules match comments
regsub {\#.+} $modules {} modules
# remove existing references to the named module from
# the list Change the module command line to reflect the
# given command
switch -- $init_cmd {
list {
if {![info exists notheader]} {
report "[getState shell] initialization file\
\$HOME/$filename loads modules:"
set notheader 0
}
report \t$modules
}
add {
foreach newmodule $init_list {
set modules [replaceFromList $modules $newmodule]
}
lappend newinit "$cmd$modules $init_list$comments"
# delete new modules in potential next lines
set init_cmd rm
}
prepend {
foreach newmodule $init_list {
set modules [replaceFromList $modules $newmodule]
}
lappend newinit "$cmd$init_list $modules$comments"
# delete new modules in potential next lines
set init_cmd rm
}
rm {
set oldmodcount [llength $modules]
foreach oldmodule $init_list {
set modules [replaceFromList $modules $oldmodule]
}
set modcount [llength $modules]
lappend newinit [expr {$modcount > 0 ?\
"$cmd$modules$comments" : [string trim $cmd]}]
if {$oldmodcount > $modcount} {
set notdone 0
}
}
switch {
set oldmodule [lindex $init_list 0]
set newmodule [lindex $init_list 1]
set newmodules [replaceFromList $modules\
$oldmodule $newmodule]
lappend newinit $cmd$newmodules$comments
if {$modules ne $newmodules} {
set notdone 0
}
}
clear {
lappend newinit [string trim $cmd]
}
}
} elseif {$curline ne {}} {
# copy the line from the old file to the new
lappend newinit $curline
}
}
if {$init_cmd ne {list} && $thismatch} {
reportDebug "Writing $filepath"
if {[catch {
set fid [open $filepath w]
puts $fid [join $newinit \n]
close $fid
} errMsg ]} {
reportErrorAndExit "Init file $filepath cannot be\
written.\n$errMsg"
}
}
}
}
}
# quit in error if command was not performed due to no match
if {$nomatch && $init_cmd ne {list}} {
reportErrorAndExit "Cannot find a 'module load' command in any of the\
'[getState shell]' startup files"
}
}
# provide access to modulefile specific commands from the command-line, making
# them standing as a module sub-command (see module procedure)
proc cmdModuleResurface {cmd args} {
lappendState mode load
lappendState commandname $cmd
set optlist [list]
switch -- $cmd {
prepend-path - append-path - remove-path {
# by-pass any reference counter, as call is from top level
# append/prepend-path: not to increase reference counter if paths are
# already defined. remove-path: to ensure paths are removed whatever
# their reference counter value
lappend optlist --ignore-refcount
}
}
# run modulefile command and get its result
if {[catch {$cmd {*}$optlist {*}$args} res]} {
# report error if any and return false
reportError $res
} else {
# register result depending of return kind (false or text)
switch -- $cmd {
module-info {
set ::g_return_text $res
}
default {
if {$res == 0} {
# render false if command returned false
setState return_false 1
}
}
}
}
lpopState commandname
lpopState mode
}
proc cmdModuleTest {args} {
lappendState mode test
set first_report 1
foreach mod $args {
lassign [getPathToModule $mod] modfile modname modnamevr
if {$modfile ne {}} {
# only one separator lines between 2 modules
if {$first_report} {
displaySeparatorLine
set first_report 0
}
report "Module Specific Test for [sgr hi $modfile]:\n"
execute-modulefile $modfile $modname modnamevr $mod
displaySeparatorLine
}
}
lpopState mode
}
proc cmdModuleClear {args} {
# fetch confirmation if no arg passed and force mode disabled
if {[llength $args] == 0 && ![getState force]} {
# ask for it if stdin is attached to a terminal
if {![catch {fconfigure stdin -mode}]} {
report "Are you sure you want to clear all loaded modules!? \[n\] " 1
flush [getState reportfd]
}
# fetch stdin content even if not attached to terminal in case some
# content has been piped to this channel
set doit [gets stdin]
} else {
set doit [lindex $args 0]
}
# should be confirmed or forced to proceed
if {[string equal -nocase -length 1 $doit y] || [getState force]} {
lappendState mode load
# unset all Modules runtime variables
foreach globvar [getModulesEnvVarGlobList 1] {
foreach var [array names ::env -glob $globvar] {
unset-env $var
}
}
lpopState mode
} else {
reportInfo "Modules runtime information were not cleared"
}
}
proc cmdModuleState {args} {
if {[llength $args] > 0} {
set name [lindex $args 0]
}
if {[info exists name] && $name ni [concat [array names ::g_state_defs]\
[array names ::g_states]]} {
knerror "State '$name' does not exist"
}
# report module version unless if called by cmdModuleConfig
if {[getCallingProcName] ne {cmdModuleConfig}} {
reportVersion
reportSeparateNextContent
}
displayTableHeader hi {State name} 24 {Value} 54
# fetch specified state or all states
if {[info exists name]} {
if {$name in [array names ::g_state_defs]} {
set stateval($name) [getState $name <undef> 1]
} else {
set stateval($name) [getState $name]
}
} else {
# define each attribute/fetched state value pair
foreach state [array names ::g_state_defs] {
set stateval($state) [getState $state <undef> 1]
}
# also get dynamic states (with no prior definition)
foreach state [array names ::g_states] {
if {![info exists stateval($state)]} {
set stateval($state) [getState $state]
}
}
}
foreach state [lsort [array names stateval]] {
append displist [format {%-25s %s} $state $stateval($state)] \n
}
report $displist 1
reportSeparateNextContent
# only report specified state if any
if {[info exists name]} {
return
}
# report environment variable set related to Modules
displayTableHeader hi {Env. variable} 24 {Value} 54
set envvar_list {}
foreach var [getModulesEnvVarGlobList] {
lappend envvar_list {*}[array names ::env -glob $var]
}
unset displist
foreach var [lsort -unique $envvar_list] {
append displist [format {%-25s %s} $var $::env($var)] \n
}
report $displist 1
}
proc cmdModuleConfig {dump_state args} {
# parse arguments
set nameunset 0
switch -- [llength $args] {
1 {
lassign $args name
}
2 {
lassign $args name value
# check if configuration should be set or unset
if {$name eq {--reset}} {
set name $value
set nameunset 1
unset value
}
}
}
reportDebug "dump_state='$dump_state', reset=$nameunset,\
name=[expr {[info exists name] ? "'$name'" : {<undef>}}], value=[expr\
{[info exists value] ? "'$value'" : {<undef>}}]"
foreach option [array names ::g_config_defs] {
lassign $::g_config_defs($option) confvar($option) defval\
conflockable($option) confkind($option) confvalid($option) vtrans\
initproc confvalidkind($option)
set confval($option) [getConf $option <undef>]
set confvtrans($option) {}
for {set i 0} {$i < [llength $vtrans]} {incr i} {
lappend confvtrans($option) [lindex $vtrans $i] [lindex\
$confvalid($option) $i]
}
}
# catch any environment variable set for modulecmd run-time execution
foreach runenvvar [array names ::env -glob MODULES_RUNENV_*] {
set runenvconf [string tolower [string range $runenvvar 8 end]]
set confval($runenvconf) [get-env $runenvvar]
# enable modification of runenv conf
set confvar($runenvconf) $runenvvar
set confvalid($runenvconf) {}
set conflockable($runenvconf) {}
set confkind($runenvconf) s
set confvtrans($runenvconf) {}
set confvalidkind($runenvconf) {}
}
if {[info exists name] && ![info exists confval($name)]} {
reportErrorAndExit "Configuration option '$name' does not exist"
# set configuration
} elseif {[info exists name] && ($nameunset || [info exists value])} {
# append or subtract value to existing configuration value if new value
# starts with '+' or '-' (for colon-separated list option only)
if {[info exists value] && $confkind($name) eq {l}} {
set curconfvallist [split [getConf $name] :]
switch -- [string index $value 0] {
+ {
appendNoDupToList curconfvallist {*}[split [string range\
$value 1 end] :]
set value [join $curconfvallist :]
}
- {
lassign [getDiffBetweenList $curconfvallist [split [string\
range $value 1 end] :]] curconfvallist
set value [join $curconfvallist :]
}
}
}
if {$confvar($name) eq {}} {
reportErrorAndExit "Configuration option '$name' cannot be altered"
} elseif {$conflockable($name) eq {1} && [isConfigLocked $name]} {
reportErrorAndExit "Configuration option '$name' is locked"
} elseif {$nameunset} {
# unset configuration variable
lappendState mode load
unsetenv $confvar($name)
lpopState mode
} elseif {[llength $confvalid($name)] > 0} {
switch -- $confvalidkind($name) {
eltlist {
# check each element in value list
if {[isDiffBetweenList [split $value :] $confvalid($name)]} {
reportErrorAndExit "Invalid element in value list for\
config. option '$name'\nAllowed elements are:\
$confvalid($name) (separated by ':')"
} else {
set validval 1
}
}
intbe {
if {[string is integer -strict $value] && $value >= [lindex\
$confvalid($name) 0] && $value <= [lindex $confvalid($name)\
1]} {
set validval 1
} else {
reportErrorAndExit "Invalid value for configuration option\
'$name'\nValue should be an integer comprised between\
[lindex $confvalid($name) 0] and [lindex\
$confvalid($name) 1]"
}
}
{} {
##nagelfar ignore +2 Non static subcommand
if {([llength $confvalid($name)] == 1 && ![string is\
$confvalid($name) -strict $value]) || ([llength\
$confvalid($name)] > 1 && $value ni $confvalid($name))} {
reportErrorAndExit "Valid values for configuration option\
'$name' are: $confvalid($name)"
} else {
set validval 1
}
}
}
} else {
set validval 1
}
if {[info exists validval]} {
# effectively set configuration variable
lappendState mode load
setenv $confvar($name) $value
lpopState mode
}
# clear cached value for config if any
unsetConf $name
# report configuration
} else {
reportVersion
reportSeparateNextContent
displayTableHeader hi {Config. name} 24 {Value (set by if default\
overridden)} 54
# report all configs or just queried one
if {[info exists name]} {
set varlist [list $name]
} else {
set varlist [lsort [array names confval]]
}
foreach var $varlist {
##nagelfar ignore +2 Suspicious variable name
set valrep [displayConfig $confval($var) $confvar($var) [info exists\
::asked_$var] $confvtrans($var) [expr {$conflockable($var) eq {1}\
&& [isConfigLocked $var]}]]
append displist [format {%-25s %s} $var $valrep] \n
}
report $displist 1
reportSeparateNextContent
if {$dump_state} {
cmdModuleState
}
}
}
proc cmdModuleShToMod {args} {
set scriptargs [lassign $args shell script]
# evaluate script and get the environment changes it performs translated
# into modulefile commands
set modcontent [sh-to-mod {*}$args]
# output resulting modulefile
if {[llength $modcontent] > 0} {
report "#%Module"
# format each command with tabs and colors if enabled
foreach modcmd $modcontent {
reportCmd -nativeargrep {*}$modcmd
}
}
}
proc cmdModuleEdit {mod} {
lassign [getPathToModule $mod] modfile modname
# error message has already been produced if mod not found or forbidden
if {$modfile ne {}} {
# redirect stdout to stderr as stdout is evaluated by module shell func
if {[catch {runCommand [getConf editor] $modfile >@stderr 2>@stderr}\
errMsg]} {
# re-throw error but as an external one (not as a module issue)
knerror $errMsg
}
}
}
proc cmdModuleRefresh {} {
lappendState mode refresh
# create an eval id to track successful/failed module evaluations
pushMsgRecordId refresh-[depthState modulename] 0
# load variants from loaded modules
cacheCurrentModules
foreach lm [getLoadedModulePropertyList refresh] {
# prepare info to execute modulefile
set vrlist [getVariantList $lm 1]
if {[llength $vrlist] > 0} {
lassign [parseModuleSpecification 0 0 0 0 $lm {*}$vrlist] lmvr
} else {
set lmvr $lm
}
set lmfile [getModulefileFromLoadedModule $lm]
set taglist [getExportTagList $lm]
# refreshing module is visible by default
set hidden 0
set uasked 1
# set a unique id to record messages related to this evaluation.
set msgrecid refresh-$lmvr-[depthState modulename]
# register record message unique id (now we know mod will be evaluated)
pushMsgRecordId $msgrecid
# record module title (with the variants and tags of loaded module)
# prior module evaluation to get this title ready in case of eval error
registerModuleDesignation $msgrecid $lm [getVariantList $lm 7]\
$taglist
# run modulefile, restore settings prior evaluation if error and
# continue to evaluate the remaining loaded modules
pushSettings
if {[set errCode [catch {
if {[execute-modulefile $lmfile $lm lmvr $lm]} {
break
}
# unloading visibility depends on hidden-loaded tag
set hidden [isModuleTagged $lm hidden-loaded 1]
# module was asked by user if tagged loaded instead of auto-loaded
set uasked [isModuleTagged $lm loaded 1]
} errMsg]] != 0 && $errCode != 4} {
restoreSettings
}
popSettings
# report all recorded messages for this evaluation (hide evaluation if
# loaded mod is set hidden, has been automatically loaded and unloaded)
reportMsgRecord "Refreshing [getModuleDesignation $msgrecid {} 2]"\
[expr {$hidden && !$uasked && [depthState evalid] != 1}]
popMsgRecordId
}
popMsgRecordId 0
lpopState mode
}
proc cmdModuleHelp {args} {
lappendState mode help
set first_report 1
foreach arg $args {
lassign [getPathToModule $arg] modfile modname modnamevr
if {$modfile ne {}} {
# only one separator lines between 2 modules
if {$first_report} {
displaySeparatorLine
set first_report 0
}
report "Module Specific Help for [sgr hi $modfile]:\n"
execute-modulefile $modfile $modname modnamevr $arg
displaySeparatorLine
}
}
lpopState mode
if {[llength $args] == 0} {
reportUsage
}
}
proc cmdModuleTag {unset_extra uasked tag_list args} {
reportDebug "tagging $args (unset_extra=$unset_extra, uasked=$uasked,\
tag_list=$tag_list)"
set ret 0
foreach mod $args {
# find mod among loaded modules
lassign [getPathToModule $mod {} 1 match] modfile modname modnamevr\
errkind
if {$modfile eq {}} {
set ret 1
# go to next module to unload
continue
}
# record tags not already set and if asked unset extra tags not set
# anymore
lassign [getDiffBetweenList $tag_list [getTagList $modname]] diff_list
lassign [getDiffBetweenList [getExtraTagList $modname] $tag_list] \
unset_list
if {[llength $diff_list] > 0 || ($unset_extra && [llength $unset_list]\
> 0)} {
# set a unique id to record messages related to this evaluation.
set msgrecid tag-$modnamevr-[depthState modulename]
pushMsgRecordId $msgrecid
# record module title (with the variant but no tag list) prior
# evaluation to get this title ready in case of error
registerModuleDesignation $msgrecid $modname [getVariantList\
$modnamevr 7] {}
lappendState mode unload
# first unset tags declared for this module on LM env var
if {[set modtag [getExportTagList $modname 1]] ne {}} {
remove-path __MODULES_LMTAG $modtag
}
if {[set modtag [getExtraTagList $modname 1]] ne {}} {
remove-path __MODULES_LMEXTRATAG $modtag
}
lpopState mode
# remove extra tags currently set not part of tag list if asked
if {$unset_extra && [llength $unset_list] > 0} {
unsetModuleTag $modname {*}$unset_list
unsetModuleExtraTag $modname {*}$unset_list
if {$modnamevr ne {} && $modname ne $modnamevr} {
unsetModuleTag $modnamevr {*}$unset_list
unsetModuleExtraTag $modnamevr {*}$unset_list
}
}
# ensure auto-loaded tag is not preserved if not part of target tags
if {$unset_extra && {auto-loaded} ni $tag_list} {
unsetModuleTag $modname auto-loaded
if {$modnamevr ne {} && $modname ne $modnamevr} {
unsetModuleTag $modnamevr auto-loaded
}
}
# record new tags as extra tag excluding tags relative to the way
# module is loaded (auto, keep)
lassign [getDiffBetweenList $diff_list [list auto-loaded\
keep-loaded]] extradiff_list
setModuleTag $modname {*}$diff_list
if {[llength $extradiff_list] > 0} {
setModuleExtraTag $modname {*}$extradiff_list
}
if {$modnamevr ne {} && $modname ne $modnamevr} {
setModuleTag $modnamevr {*}$diff_list
if {[llength $extradiff_list] > 0} {
setModuleExtraTag $modnamevr {*}$extradiff_list
}
}
# set the new tag set for module on LM env var
lappendState mode load
if {[set modtag [getExportTagList $modnamevr 1]] ne {}} {
append-path __MODULES_LMTAG $modtag
}
if {[set modtag [getExtraTagList $modnamevr 1]] ne {}} {
append-path __MODULES_LMEXTRATAG $modtag
}
lpopState mode
# update module designation now the additional tags are set
registerModuleDesignation $msgrecid $modname [getVariantList\
$modname 7] [getExportTagList $modname]
# report tagging evaluation unless hidden and auto-loaded
set hidden [isModuleTagged $modnamevr hidden-loaded 1]
reportMsgRecord "Tagging [getModuleDesignation $msgrecid {} 2]"\
[expr {$hidden && !$uasked}]
popMsgRecordId
# indicates that new tags have been applied
set ret 2
}
}
return $ret
}
proc cmdModuleLint {args} {
# stop if no linter defined
if {[llength [getConf tcl_linter]] == 0} {
knerror {No Tcl linter program configured}
}
# extract linter program name
set linter [file rootname [file tail [lindex [getConf tcl_linter] 0]]]
# build command line
set linter_mfile [getConf tcl_linter]
set linter_mrc [getConf tcl_linter]
set linter_gmrc [getConf tcl_linter]
# add module-specific syntax database in addition to regular Tcl one
@nagelfaraddons@if {$linter eq {nagelfar}} {
@nagelfaraddons@ lappend linter_mfile -s _\
@nagelfaraddons@ -s {@nagelfardatadir@/syntaxdb_modulefile.tcl}\
@nagelfaraddons@ -plugin {@nagelfardatadir@/plugin_modulefile.tcl}
@nagelfaraddons@ lappend linter_mrc -s _\
@nagelfaraddons@ -s {@nagelfardatadir@/syntaxdb_modulerc.tcl}\
@nagelfaraddons@ -plugin {@nagelfardatadir@/plugin_modulerc.tcl}
@nagelfaraddons@ lappend linter_gmrc -s _\
@nagelfaraddons@ -s {@nagelfardatadir@/syntaxdb_modulefile.tcl}\
@nagelfaraddons@ -plugin {@nagelfardatadir@/plugin_globalrc.tcl}
@nagelfaraddons@}
set global_rclist [getGlobalRcFileList]
set modfilelist {}
# fetch every available modulefiles if no argument provided
if {[llength $args] == 0} {
# add global RC files
foreach rc $global_rclist {
set tolint($rc) gmrc
}
inhibitErrorReport
foreach dir [getModulePathList exiterronundef] {
# fetch all existing rc file current user has access to
foreach {elt props} [findModules $dir * 0 0] {
switch -- [lindex $props 0] {
modulerc {
set tolint($dir/$elt) mrc
}
}
}
# collect all modulefile from dir that current user has access to
# getModules will reuse the result collected for findModules
foreach {elt props} [getModules $dir *] {
switch -- [lindex $props 0] {
modulefile - virtual {
set tolint([lindex $props 2]) mfile
}
}
}
}
setState inhibit_errreport 0
} else {
foreach mod $args {
lassign [getPathToModule $mod] modfile modname modnamevr
# error mesg has already been produced if mod not found or forbidden
if {$modfile ne {}} {
if {$modfile in $global_rclist} {
set mkind gmrc
} elseif {[file tail $modfile] in {.modulerc .version}} {
set mkind mrc
} else {
set mkind mfile
}
set tolint($modfile) $mkind
}
}
}
# execute linter program over every gathered file
foreach lintfile [lsort -dictionary [array names tolint]] {
# set a record message unique id and record modulefile title
set msgrecid lint-$lintfile
pushMsgRecordId $msgrecid
registerModuleDesignation $msgrecid $lintfile {} {}
##nagelfar ignore Suspicious variable name
if {[catch {set out [runCommand {*}[set linter_$tolint($lintfile)]\
$lintfile]} errMsg]} {
# re-throw error but as an external one (not as a module issue)
knerror $errMsg
}
# report linting messages
displayLinterOutput $linter $out
# report all lint messages for this modulefile
reportMsgRecord "Linting [getModuleDesignation $msgrecid {} 2]"
popMsgRecordId
}
}
proc cmdModuleModToSh {shell args} {
# save shell modulecmd is initialized to
##nagelfar ignore Found constant
setState modtosh_real_shell [getState shell]
# set shell and shellType states to mod-to-sh target value
if {$shell ni [getState supported_shells]} {
reportErrorAndExit "Unsupported shell type \'$shell\'"
}
##nagelfar ignore Found constant
setState shell $shell
unsetState shelltype
# silence message report (avoid mix with produced shell code) unless if
# a debugging mode is set
if {![isVerbosityLevel trace]} {
unsetConf verbosity
set ::asked_verbosity silent
}
# modulefile evaluation is done against mod-to-sh target shell which means
# module-info will return mod-to-sh shell value
return [cmdModuleLoad load 1 0 0 {} {*}$args]
# after evaluation, renderSettings will produce shell code for mod-to-sh
# target shell. modtosh_real_shell state helps to know that shell code has
# to be output on report message channel
}
proc cmdModuleReset {} {
# use reset_target_state configuration option to know the environment state
# to restore
if {[getConf reset_target_state] eq {__purge__}} {
cmdModulePurge
} else {
cmdModuleRestore [getConf reset_target_state]
}
}
proc cmdModuleStash {} {
# check if there is something to stash
if {[getConf reset_target_state] eq {__purge__}} {
# load tags from loaded modules
cacheCurrentModules
# current environment differs from initial 'purge' state when at least
# a module is loaded and it is not super-sticky and not sticky or force
# mode is enabled to allow sticky tag unload
set diff_from_init 0
foreach mod [getLoadedModulePropertyList name] {
if {![isModuleTagged $mod super-sticky 1] && (![isModuleTagged $mod\
sticky 1] || [getState force])} {
set diff_from_init 1
break
}
}
} else {
# compare current environment against initial collection to check if
# something differ
set coll [getConf reset_target_state]
# get corresponding collection or init, raise error if it does not exist
lassign [findCollections $coll exact 0 1] collfile colldesc
# fetch collection content and differences compared current environment
lassign [getDiffBetweenCurEnvAndColl $collfile $colldesc]\
coll_path_list coll_mod_list coll_tag_arrser coll_nuasked_list\
mod_to_unload mod_to_load path_to_unuse path_to_use is_tags_diff
array set coll_tag_arr $coll_tag_arrser
set diff_from_init [expr {[llength $mod_to_unload] > 0 || [llength\
$mod_to_load] > 0 || [llength $path_to_unuse] > 0 || [llength\
$path_to_use] > 0 || $is_tags_diff}]
}
if {!$diff_from_init} {
reportWarning {No specific environment to save}
return
}
# record current environment
cmdModuleSave stash-[clock milliseconds]
# restore initial environment
cmdModuleReset
}
proc cmdModuleStashpop {{stash 0}} {
# determine stash collection name from argument
set coll [getCollectionFromStash $stash]
# restore stash collection environment state
cmdModuleRestore $coll
# delete stash collection file
cmdModuleSaverm $coll
}
proc cmdModuleStashrm {{stash 0}} {
# determine stash collection name from argument
set coll [getCollectionFromStash $stash]
# delete stash collection file
cmdModuleSaverm $coll
}
proc cmdModuleStashshow {{stash 0}} {
# determine stash collection name from argument
set coll [getCollectionFromStash $stash]
# display stash collection file
cmdModuleSaveshow $coll
}
proc cmdModuleStashclear {} {
# get all stash collections (only from current target)
set collfile_list [findCollections stash-* glob 0 0 1 1]
# delete all stash collections starting from most recent
foreach collfile [lsort -decreasing $collfile_list] {
# extract collection name (without path and target extension)
set coll [file rootname [file tail $collfile]]
# delete stash collection file
cmdModuleSaverm $coll
}
}
proc cmdModuleStashlist {show_oneperline show_mtime} {
cmdModuleSavelist $show_oneperline $show_mtime {} stash-*
}
proc cmdModuleCachebuild {args} {
# use enabled modulepaths when no arg is provided
if {[llength $args] > 0} {
set modpath_list $args
} else {
set modpath_list [getModulePathList exiterronundef]
}
# record cache with module header check options enabled
setConf mcookie_check always
setConf mcookie_version_check 1
# ignore cache when building cache
setConf ignore_cache 1
foreach modpath $modpath_list {
set cachefile [getModuleCacheFilename $modpath]
# set a record message unique id and record cachefile title
set msgrecid cachebuild-$cachefile
pushMsgRecordId $msgrecid
registerModuleDesignation $msgrecid $cachefile {} {}
if {[file isdirectory $modpath]} {
if {[file writable $modpath]} {
if {[catch {
# get cache content for modulepath
set cache [formatModuleCacheContent $modpath]
if {[string length $cache] == 0} {
reportWarning {Nothing to record in cache file}
} else {
# record cache content in file
set fid [open $cachefile w]
# use defined buffer size to limit num of write system call
fconfigure $fid -buffersize [getConf cache_buffer_bytes]
puts $fid $cache
close $fid
}
} errMsg]} {
# report error occurring during cache content format or cache
# file write
reportError $errMsg
}
} else {
reportWarning {Cannot build cache file, directory is not writable}
}
} else {
reportError "'$modpath' is not a directory"
}
# report all messages for this cachefile creation
reportMsgRecord "Creating [getModuleDesignation $msgrecid {} 2]"
popMsgRecordId
}
}
proc cmdModuleCacheclear {} {
foreach modpath [getModulePathList exiterronundef] {
set cachefile [getModuleCacheFilename $modpath]
if {[file exists $cachefile]} {
# set a record message unique id and record cachefile title
set msgrecid cacheclear-$cachefile
pushMsgRecordId $msgrecid
registerModuleDesignation $msgrecid $cachefile {} {}
if {[file writable $modpath]} {
if {[catch {file delete $cachefile} errMsg]} {
reportError $errMsg
}
} else {
reportWarning {Cannot remove cache file, directory is not\
writable}
}
# report all messages for this cachefile deletion
reportMsgRecord "Deleting [getModuleDesignation $msgrecid {} 2]"
popMsgRecordId
}
}
}
# ;;; Local Variables: ***
# ;;; mode:tcl ***
# ;;; End: ***
# vim:set tabstop=3 shiftwidth=3 expandtab autoindent: