Files
modules/tcl/coll.tcl
Xavier Delaruelle 3a1339b6fa Check loaded/auto-loaded tag rather specific struct/proc
Remove the isModuleUserAsked procedure and g_loadedModuleUasked array.
Check if the 'loaded' or 'auto-loaded' tag is set instead.
2021-08-01 19:07:16 +02:00

254 lines
9.3 KiB
Tcl

##########################################################################
# COLL.TCL, collection management procedures
# Copyright (C) 2016-2021 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/>.
##########################################################################
# build list of what to undo then do to move from an initial list to a target
# list, eventually checking element presence in extra from/to lists
proc getMovementBetweenList {from to {extfrom {}} {extto {}} {cmp eq}} {
reportDebug "from($from) to($to) with extfrom($extfrom) extto($extto)"
set undo {}
set do {}
# determine what element to undo then do
# to restore a target list from a current list
# with preservation of the element order
set imax [if {[llength $to] > [llength $from]} {llength $to} {llength\
$from}]
set list_equal 1
for {set i 0} {$i < $imax} {incr i} {
set to_obj [lindex $to $i]
set from_obj [lindex $from $i]
# check from/to element presence in extra from/to list
set in_extfrom [expr {$from_obj in $extfrom}]
set in_extto [expr {$to_obj in $extto}]
# are elts the sames and are both part of or missing from extra lists
# when comparing modules, ask comparison against loaded module
# alternative and simplified names (modEq will also compare variants)
if {($cmp eq {modeq} && ![modEq $to_obj $from_obj equal 1 3 1]) ||\
($cmp eq {eq} && $to_obj ne $from_obj) || $in_extfrom != $in_extto} {
set list_equal 0
}
if {$list_equal == 0} {
if {$to_obj ne {}} {
lappend do $to_obj
}
if {$from_obj ne {}} {
lappend undo $from_obj
}
}
}
return [list $undo $do]
}
# build list of currently loaded modules where modulename is registered minus
# module version if loaded version is the default one
proc getSimplifiedLoadedModuleList {} {
set curr_mod_list {}
set curr_nuasked_list {}
set modpathlist [getModulePathList]
foreach mod [getLoadedModuleList] {
set altandsimplist [getLoadedAltAndSimplifiedName $mod]
set parentmod [file dirname $mod]
set simplemod $mod
# simplify to parent name as long as it is found in simplified name list
while {$parentmod ne {.}} {
if {$parentmod in $altandsimplist} {
set simplemod $parentmod
set parentmod [file dirname $parentmod]
} else {
set parentmod .
}
}
# add each module specification as list to correctly enclose spaces in
# module name or variant name or value
set simplemodvr [list $simplemod {*}[getVariantList $mod 5 1]]
lappend curr_mod_list $simplemodvr
# record not user asked module list in simplified version form
if {[isModuleTagged $mod auto-loaded 1]} {
lappend curr_nuasked_list $simplemodvr
}
}
return [list $curr_mod_list $curr_nuasked_list]
}
# return saved collections found in user directory which corresponds to
# enabled collection target if any set.
proc findCollections {} {
if {[info exists ::env(HOME)]} {
set coll_search $::env(HOME)/.module/*
} else {
reportErrorAndExit {HOME not defined}
}
# find saved collections (matching target suffix)
# a target is a domain on which a collection is only valid.
# when a target is set, only the collections made for that target
# will be available to list and restore, and saving will register
# the target footprint
set colltarget [getConf collection_target]
if {$colltarget ne {}} {
append coll_search .$colltarget
}
# glob excludes by default files starting with "."
if {[catch {set coll_list [glob -nocomplain $coll_search]} errMsg]} {
reportErrorAndExit "Cannot access collection directory.\n$errMsg"
}
return $coll_list
}
# get filename corresponding to collection name provided as argument.
# name provided may already be a file name. collection description name
# (with target info if any) is returned along with collection filename
proc getCollectionFilename {coll} {
# initialize description with collection name
set colldesc $coll
if {$coll eq {}} {
reportErrorAndExit [getEmptyNameMsg collection]
# is collection a filepath
} elseif {[string first / $coll] > -1} {
# collection target has no influence when
# collection is specified as a filepath
set collfile $coll
# elsewhere collection is a name
} elseif {[info exists ::env(HOME)]} {
set collfile $::env(HOME)/.module/$coll
# if a target is set, append the suffix corresponding
# to this target to the collection file name
set colltarget [getConf collection_target]
if {$colltarget ne {}} {
append collfile .$colltarget
# add knowledge of collection target on description
append colldesc " (for target \"$colltarget\")"
}
} else {
reportErrorAndExit {HOME not defined}
}
return [list $collfile $colldesc]
}
# generate collection content based on provided path and module lists
proc formatCollectionContent {path_list mod_list nuasked_list {sgr 0}} {
set content {}
# graphically enhance module command if asked
set modcmd [expr {$sgr ? [sgr cm module] : {module}}]
# start collection content with modulepaths
foreach path $path_list {
# enclose path if space character found in it
if {[string first { } $path] != -1} {
set path "{$path}"
}
# 'module use' prepends paths by default so we clarify
# path order here with --append flag
append content "$modcmd use --append $path" \n
}
# then add modules
foreach mod $mod_list {
# mark modules not asked by user to restore the user asked state
set opt [expr {$mod in $nuasked_list ? {--notuasked } : {}}]
# no need to specifically enclose module specification if space char
# used in it as $mod is a list so elements including space will be
# automatically enclosed
append content "$modcmd load $opt$mod" \n
}
return $content
}
# read given collection file and return the path and module lists it defines
proc readCollectionContent {collfile colldesc} {
# init lists (maybe coll does not set mod to load)
set path_list {}
set mod_list {}
set nuasked_list {}
# read file
if {[catch {
set fdata [split [readFile $collfile] \n]
} errMsg ]} {
reportErrorAndExit "Collection $colldesc cannot be read.\n$errMsg"
}
# analyze collection content
foreach fline $fdata {
if {[regexp {module use (.*)$} $fline match patharg] == 1} {
# paths are appended by default
set stuff_path append
# manage multiple paths and path options specified on single line,
# for instance "module use --append path1 path2 path3", with list
# representation of patharg (which handles quoted elements containing
# space in their name)
foreach path $patharg {
# following path is asked to be appended
if {($path eq {--append}) || ($path eq {-a})\
|| ($path eq {-append})} {
set stuff_path append
# following path is asked to be prepended
# collection generated with 'save' does not prepend
} elseif {($path eq {--prepend}) || ($path eq {-p})\
|| ($path eq {-prepend})} {
set stuff_path prepend
} else {
# ensure given path is absolute to be able to correctly
# compare with paths registered in MODULEPATH
set path [getAbsolutePath $path]
# add path to end of list
if {$stuff_path eq {append}} {
lappend path_list $path
# insert path to first position
} else {
set path_list [linsert $path_list 0 $path]
}
}
}
} elseif {[regexp {module load (.*)$} $fline match modarg] == 1} {
# remove collection-specific flags in specification
set cleanlist [lsearch -all -inline -not -exact $modarg\
--notuasked]
# parse module specification to distinguish between module + variant
# specif and multiple modules specified on a single line
set parsedlist [parseModuleSpecification 0 {*}$cleanlist]
if {[llength $modarg] != [llength $cleanlist]} {
foreach parsed $parsedlist {
# add module name version and variant spec to the list
lappend nuasked_list $parsed
}
}
lappend mod_list {*}$parsedlist
}
}
return [list $path_list $mod_list $nuasked_list]
}
# ;;; Local Variables: ***
# ;;; mode:tcl ***
# ;;; End: ***
# vim:set tabstop=3 shiftwidth=3 expandtab autoindent: