Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 54 additions & 5 deletions tcl/modfind.tcl.in
Original file line number Diff line number Diff line change
Expand Up @@ -2955,7 +2955,7 @@ proc findModulesInMemCache {searchid} {
# Walk through provided list of directories and files to find modules
proc findModulesFromDirsAndFiles {dir full_list depthlvl fetch_mtime\
res_arrname {indir_arrname {}} {hidden_listname {}} {fknown_arrname {}}\
{dknown_arrname {}}} {
{dknown_arrname {}} {prunespec {}}} {
# link to variables/arrays from upper context
upvar $res_arrname mod_list
if {$indir_arrname ne {}} {
Expand All @@ -2971,6 +2971,15 @@ proc findModulesFromDirsAndFiles {dir full_list depthlvl fetch_mtime\
upvar $dknown_arrname dknown_arr
}

# build pruning path components from spec (e.g. tools/cat15/pkg10/3.0 ->
# {tools cat15 pkg10 3.0}) to skip non-matching directories during walk
if {$prunespec ne {}} {
set pruneparts [file split $prunespec]
set prunedepth [llength $pruneparts]
} else {
set prunedepth 0
}

foreach igndir [getConf ignored_dirs] {
set ignored_dirs($igndir) 1
}
Expand All @@ -2986,6 +2995,23 @@ proc findModulesFromDirsAndFiles {dir full_list depthlvl fetch_mtime\
if {[info exists dknown_arr($modulename)] || (![info exists\
fknown_arr($modulename)] && [file isdirectory $element])} {
if {![info exists ignored_dirs($tail)]} {
# prune directories that cannot match the query path: read
# dir for .modulerc/.version but skip subdirs and files
if {$prunedepth > 0 && $moddepthlvl <= $prunedepth && [lindex\
$pruneparts [expr {$moddepthlvl - 1}]] ne $tail} {
if {![catch {
set elt_list [getFilesInDirectory $element 1]
}]} {
foreach {fpelt hid} $elt_list {
set fptail [file tail $fpelt]
if {$fptail eq {.modulerc} || $fptail eq\
{.version}} {
lappend full_list $fpelt
}
}
}
continue
}
if {[catch {
set elt_list [getFilesInDirectory $element 1]
} errMsg]} {
Expand Down Expand Up @@ -3051,12 +3077,12 @@ proc findModulesFromDirsAndFiles {dir full_list depthlvl fetch_mtime\
}

# finds all module-related files matching mod in the module path dir
proc findModules {dir mod depthlvl fetch_mtime} {
proc findModules {dir mod depthlvl fetch_mtime {prunespec {}}} {
reportDebug "finding '$mod' in $dir (depthlvl=$depthlvl,\
fetch_mtime=$fetch_mtime)"

# generated search id (for cache search/save) by compacting given args
set searchid $dir:$mod:$depthlvl:$fetch_mtime
set searchid $dir:$mod:$depthlvl:$fetch_mtime:$prunespec

# look at memory cache for a compatible result
lassign [findModulesInMemCache $searchid] cache_searchid cache_list
Expand Down Expand Up @@ -3095,7 +3121,8 @@ proc findModules {dir mod depthlvl fetch_mtime} {
}

# walk through list of dirs and files to find modules
findModulesFromDirsAndFiles $dir $full_list $depthlvl $fetch_mtime mod_list
findModulesFromDirsAndFiles $dir $full_list $depthlvl $fetch_mtime \
mod_list {} {} {} {} $prunespec

reportDebug "found [array names mod_list]"

Expand Down Expand Up @@ -3201,7 +3228,29 @@ proc getModules {dir {mod {}} {fetch_mtime 0} {search {}} {filter {}}} {
# unless EMS need to be performed (findModules should fetch everything)
set depthlvl [expr {$indepth || $ems_required ? 0 : $querydepth + 1}]

array set found_list [findModules $dir $findmod $depthlvl $fetch_mtime]
# enable directory pruning when query is a specific deep path without
# wildcards (e.g. tools/cat15/pkg10/3.0) to avoid scanning sibling
# directories that cannot match; verify every path component exists
# on disk so virtual names (symbols/aliases) do not trigger pruning
set prunespec {}
if {$hasmoddir && !$find_all && !$contains && $modqe eq\
[string map {* {} ? {}} $modqe]} {
set _canprune 1
set _checkpath $dir
foreach _qp [file split $modqe] {
set _checkpath [file join $_checkpath $_qp]
if {![file isdirectory $_checkpath]} {
set _canprune 0
break
}
}
if {$_canprune} {
set prunespec $modqe
}
}

array set found_list [findModules $dir $findmod $depthlvl $fetch_mtime\
$prunespec]
}

# Phase #1: consolidate every kind of entries (directory, modulefile,
Expand Down
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat1/.modulerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-alias prunetest/shortcut prunetest/cat2/pkg1/1.0
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat1/pkg1/1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat1/pkg1/2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat1/pkg2/1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat1/pkg2/2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat2/pkg1/1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat2/pkg1/2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat2/pkg2/1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
2 changes: 2 additions & 0 deletions testsuite/modulefiles.deep/prunetest/cat2/pkg2/2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%Module1.0
module-whatis "prunetest/$d/$v"
60 changes: 60 additions & 0 deletions testsuite/modules.80-deep/026-pruning-deep.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
##############################################################################
# Modules Revision 3.0
# Providing a flexible user environment
#
# Description: Directory pruning for deep module queries
# Command: avail, load
# Modulefiles: prunetest/cat{1,2}/pkg{1,2}/{1.0,2.0}
#
# Test that specific deep queries correctly return matching modules
# when directory pruning skips non-matching sibling directories.
# Ensures pruning does not omit valid results and broad queries
# still return everything.
#
##############################################################################

# use deep modulefiles path for these tests
set deepmodpath "$env(TESTSUITEDIR)/modulefiles.deep"
setenv_path_var MODULEPATH $deepmodpath

# ensure auto symbolic versions are not set for these tests
setenv_var MODULES_ADVANCED_VERSION_SPEC 0

# avail on specific 3-level deep path should return only that pkg
set ts_sh "$deepmodpath:\nprunetest/cat1/pkg1/1.0\nprunetest/cat1/pkg1/2.0"
testouterr_cmd "sh" "avail -t prunetest/cat1/pkg1" "OK" $ts_sh

# avail on 2-level deep path returns all pkgs under that category
set ts_sh "$deepmodpath:\nprunetest/cat1/pkg1/1.0\nprunetest/cat1/pkg1/2.0\nprunetest/cat1/pkg2/1.0\nprunetest/cat1/pkg2/2.0"
testouterr_cmd "sh" "avail -t prunetest/cat1" "OK" $ts_sh

skip_if_quick_mode

# avail on the top level returns all modules (no pruning)
set ts_sh "$deepmodpath:\nprunetest/cat1/pkg1/1.0\nprunetest/cat1/pkg1/2.0\nprunetest/cat1/pkg2/1.0\nprunetest/cat1/pkg2/2.0\nprunetest/cat2/pkg1/1.0\nprunetest/cat2/pkg1/2.0\nprunetest/cat2/pkg2/1.0\nprunetest/cat2/pkg2/2.0"
testouterr_cmd "sh" "avail -t prunetest" "OK" $ts_sh

# avail on exact version path
set ts_sh "$deepmodpath:\nprunetest/cat2/pkg2/2.0"
testouterr_cmd "sh" "avail -t prunetest/cat2/pkg2/2.0" "OK" $ts_sh

# load a specific deep module
set ans [list]
lappend ans [list set _LMFILES_ \
"$deepmodpath/prunetest/cat1/pkg2/1.0"]
lappend ans [list set LOADEDMODULES "prunetest/cat1/pkg2/1.0"]
test_cmd_re "sh" "load prunetest/cat1/pkg2/1.0" $ans

# wildcard query should not be pruned and return all matches
set ts_sh "$deepmodpath:\nprunetest/cat1/pkg1/1.0\nprunetest/cat1/pkg1/2.0\nprunetest/cat2/pkg1/1.0\nprunetest/cat2/pkg1/2.0"
testouterr_cmd_re "sh" "avail -t prunetest/*/pkg1" "OK" $ts_sh

# cross-directory alias: cat1/.modulerc defines prunetest/shortcut
# pointing to cat2/pkg1/1.0; pruning cat1 must still find the alias
set ts_sh "$deepmodpath:\nprunetest/shortcut"
testouterr_cmd "sh" "avail -t prunetest/shortcut" "OK" $ts_sh

# cleanup
setenv_path_var MODULEPATH $modpath
unsetenv_var MODULES_ADVANCED_VERSION_SPEC
unset ts_sh ans deepmodpath