From fda9de1bdee9519ee5ac61d654427110f30a0e2c Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Wed, 22 Jul 2026 17:53:18 +0200 Subject: [PATCH 1/5] Fix source-sh/sh-to-mod value change with mixed delimiters When a path-like environment variable change requires both a prepended and an appended part expressed with a different delimiter character, describing it as a prepend-path and an append-path command does not produce a consistent value: each command independently splits and de-duplicates the full variable value using its own delimiter. A setenv command directly setting the resulting value is generated instead in this situation. Signed-off-by: Xavier Delaruelle --- NEWS.rst | 5 ++ .../source-shell-script-in-modulefile.rst | 7 ++ tcl/mfcmd.tcl | 83 +++++++++++-------- testsuite/modules.70-maint/310-sh-to-mod.exp | 29 +++---- .../modules.70-maint/311-eval-sh-to-mod.exp | 27 +++--- 5 files changed, 85 insertions(+), 66 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 7f9cbed8c..31d932df0 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -137,6 +137,11 @@ Modules 5.7.0 (not yet released) :instopt:`--with-domainname` and :instopt:`--with-domainname-opts` options. When :mconfig:`domainname` is changed with :subcmd:`config` sub-command, it sets the :envvar:`MODULES_DOMAINNAME` environment variable. (fix issue #645) +* Update the :mfcmd:`source-sh` modulefile command and :subcmd:`sh-to-mod` + sub-command mechanism to produce a more consistent value for a path-like + environment variable change that requires both a prepended and an appended + part expressed with a different delimiter character: a :mfcmd:`setenv` + command is now generated instead in this situation. .. _5.6 release notes: diff --git a/doc/source/design/source-shell-script-in-modulefile.rst b/doc/source/design/source-shell-script-in-modulefile.rst index 3c13d065e..1c14bdcb6 100644 --- a/doc/source/design/source-shell-script-in-modulefile.rst +++ b/doc/source/design/source-shell-script-in-modulefile.rst @@ -194,6 +194,13 @@ Specification - An environment variable equaling to the path separator character (``:``) prior script evaluation is considered as undefined prior script evaluation to avoid misleading analysis +- Path-like variable change is recorded as a ``setenv`` command instead of ``prepend-path`` and ``append-path`` commands when the newly prepended and newly appended parts would each need a different delimiter character to be expressed + + - Prior and after variable values are compared to find a common part between them: what is found before this common part is expressed as a ``prepend-path`` command and what is found after it as an ``append-path`` command + - Each of these two commands may need its own delimiter character, determined from the character found in the after value right before (for the prepended part) or right after (for the appended part) the common part, when this character is not the variable path separator + - When the delimiter character determined for the prepended part differs from the one determined for the appended part, describing the change as a ``prepend-path`` and an ``append-path`` command would not correctly reproduce the resulting value, as each command would independently split and de-duplicate the full variable value using its own delimiter + - A ``setenv`` command directly setting the after value is generated instead in this situation, to always accurately reflect the change made by the script + - Environment variables made for Modules private use are filtered-out from the environment changes produced - ``LOADEDMODULES``, ``_LMFILES_`` and any variable prefixed by ``__MODULES_`` are concerned diff --git a/tcl/mfcmd.tcl b/tcl/mfcmd.tcl index 5821b31ca..524221483 100644 --- a/tcl/mfcmd.tcl +++ b/tcl/mfcmd.tcl @@ -1682,45 +1682,62 @@ proc sh-to-mod {elt_ignored_list args} { $varbef($name) $varaft($name)]] == -1} { lappend modcontent [list setenv $name $varaft($name)] } else { - # content should be prepended - if {$idx > 0} { - set modcmd [list prepend-path] + set doprepend [expr {$idx > 0}] + if {$doprepend} { # check from the end to get the largest chunk to prepend set idx [string last $varbef($name) $varaft($name)] # get delimiter from char found between new and existing value - set delim [string index $varaft($name) $idx-1] - if {$delim ne $pathsep} { - lappend modcmd -d $delim - } - lappend modcmd $name - # split value and remove duplicate entries - set vallist [list] - lappendNoDup vallist {*}[split [string range $varaft($name) 0\ - $idx-2] $delim] - # an empty element is added - if {![llength $vallist]} { - lappend vallist {} - } - lappend modcontent [list {*}$modcmd {*}$vallist] + set predelim [string index $varaft($name) $idx-1] + } + set doappend [expr {($idx + [string length $varbef($name)]) <\ + [string length $varaft($name)]}] + if {$doappend} { + set appdelim [string index $varaft($name) $idx+[string\ + length $varbef($name)]] } - # content should be appended - if {($idx + [string length $varbef($name)]) < [string length\ - $varaft($name)]} { - set modcmd [list append-path] - set delim [string index $varaft($name) $idx+[string length\ - $varbef($name)]] - if {$delim ne $pathsep} { - lappend modcmd -d $delim + + # if content must both be prepended and appended but each side + # uses a different delimiter character, the change cannot be + # expressed as a coherent pair of path-manipulation commands, + # since each delimiter implies a different, incompatible split + # of the value: fall back to a plain setenv to correctly + # capture the new value + if {$doprepend && $doappend && $predelim ne $appdelim} { + lappend modcontent [list setenv $name $varaft($name)] + } else { + # content should be prepended + if {$doprepend} { + set modcmd [list prepend-path] + if {$predelim ne $pathsep} { + lappend modcmd -d $predelim + } + lappend modcmd $name + # split value and remove duplicate entries + set vallist [list] + lappendNoDup vallist {*}[split [string range\ + $varaft($name) 0 $idx-2] $predelim] + # an empty element is added + if {![llength $vallist]} { + lappend vallist {} + } + lappend modcontent [list {*}$modcmd {*}$vallist] } - lappend modcmd $name - set vallist [list] - lappendNoDup vallist {*}[split [string range $varaft($name)\ - [expr {$idx + [string length $varbef($name)] + 1}] end]\ - $delim] - if {![llength $vallist]} { - lappend vallist {} + # content should be appended + if {$doappend} { + set modcmd [list append-path] + if {$appdelim ne $pathsep} { + lappend modcmd -d $appdelim + } + lappend modcmd $name + set vallist [list] + lappendNoDup vallist {*}[split [string range\ + $varaft($name) [expr {$idx + [string length\ + $varbef($name)] + 1}] end] $appdelim] + if {![llength $vallist]} { + lappend vallist {} + } + lappend modcontent [list {*}$modcmd {*}$vallist] } - lappend modcontent [list {*}$modcmd {*}$vallist] } } } diff --git a/testsuite/modules.70-maint/310-sh-to-mod.exp b/testsuite/modules.70-maint/310-sh-to-mod.exp index 646024455..251a59fc6 100644 --- a/testsuite/modules.70-maint/310-sh-to-mod.exp +++ b/testsuite/modules.70-maint/310-sh-to-mod.exp @@ -608,19 +608,16 @@ setenv_var FOOPATHSP "/path/to/dir2 /path" setenv_var FOOPATHSPEM "/path/to/dir2 /path" setenv_var FOOPATHCB "/path/to/d{r2:/path" setenv_var FOOPATHWC "/path/to/d*r2:/path" +# the prepend and append chunks here would use a different delimiter +# character ('/' vs ':'): a plain setenv is used instead of the two path +# commands, to produce a more consistent value set tserr "#%Module -append-path\t-d / FOOPATH to dir3 -append-path\t-d / FOOPATHCB to dir3 -append-path\t-d / FOOPATHEM to dir3 -append-path\t-d / FOOPATHSP to dir3 -append-path\t-d / FOOPATHSPEM to {dir3 } -append-path\t-d / FOOPATHWC to dir3 -prepend-path\t-d { } FOOPATHSP /path/to/dir1 -prepend-path\t-d { } FOOPATHSPEM /path/to/dir1 -prepend-path\tFOOPATH /path/to/dir1 -prepend-path\tFOOPATHCB /path/to/dir1 -prepend-path\tFOOPATHEM {} /path/to/dir1 -prepend-path\tFOOPATHWC /path/to/dir1" +setenv\t\tFOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 +setenv\t\tFOOPATHCB /path/to/dir1:/path/to/d\\{r2:/path/to/dir3 +setenv\t\tFOOPATHEM :/path/to/dir1:/path/to/dir2:/path/to/dir3 +setenv\t\tFOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} +setenv\t\tFOOPATHSPEM {/path/to/dir1 /path/to/dir2 /path/to/dir3 } +setenv\t\tFOOPATHWC /path/to/dir1:/path/to/d*r2:/path/to/dir3" testouterr_shtomod ALL {} OK $tserr unsetenv_var FOOPATH unsetenv_var FOOPATHEM @@ -686,12 +683,11 @@ append-path\t-d { } FOOPATHDUPSP /path/to/dir3 /path/to:dir4 append-path\t-d { } FOOPATHDUPSPEM /path/to/dir3 {} append-path\tFOOPATHDUP /path/to/dir3 {/path/to dir4} append-path\tFOOPATHDUPEM /path/to/dir3 {} -append-path\tFOOPATHDUPMIX /path/to/dir3 {} -prepend-path\t-d { } FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1 prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 prepend-path\tFOOPATHDUP /path/to/dir1 -prepend-path\tFOOPATHDUPEM {} /path/to/dir1" +prepend-path\tFOOPATHDUPEM {} /path/to/dir1 +setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr # ambiguous prior value @@ -729,14 +725,13 @@ setenv_var FOOPATHDUPMIX "/path/to/dir1 /path/to/dir2" setenv_var FOOPATHDUPSP {/path/to:dir4} setenv_var FOOPATHDUPSPEM {/path/to/dir3 } set tserr "#%Module -append-path\t-d { } FOOPATHDUPMIX /path/to/dir1:/path/to/dir3:/path/to/dir3: append-path\t-d { } FOOPATHDUPSP /path/to/dir3 append-path\tFOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir3 {/path/to dir4} append-path\tFOOPATHDUPEM /path/to/dir3 prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir3 prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir2 /path/to/dir3 prepend-path\tFOOPATHDUPEM {} /path/to/dir1 /path/to/dir2 -prepend-path\tFOOPATHDUPMIX {} /path/to/dir1" +setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr unsetenv_var TESTSUITE_SHTOMOD_PATHDUP diff --git a/testsuite/modules.70-maint/311-eval-sh-to-mod.exp b/testsuite/modules.70-maint/311-eval-sh-to-mod.exp index f0f34f979..42d31fd5f 100644 --- a/testsuite/modules.70-maint/311-eval-sh-to-mod.exp +++ b/testsuite/modules.70-maint/311-eval-sh-to-mod.exp @@ -296,19 +296,16 @@ setenv_var FOOPATHSP "/path/to/dir2 /path" setenv_var FOOPATHSPEM "/path/to/dir2 /path" setenv_var FOOPATHCB "/path/to/d{r2:/path" setenv_var FOOPATHWC "/path/to/d*r2:/path" +# the prepend and append chunks here would use a different delimiter +# character ('/' vs ':'): a plain setenv is used instead of the two path +# commands, to produce a more consistent value set tserr "#%Module -append-path\t-d / FOOPATH dir3 -append-path\t-d / FOOPATHCB dir3 -append-path\t-d / FOOPATHEM dir3 -append-path\t-d / FOOPATHSP dir3 -append-path\t-d / FOOPATHSPEM {dir3 } -append-path\t-d / FOOPATHWC dir3 -prepend-path\t-d { } FOOPATHSP /path/to/dir1 -prepend-path\t-d { } FOOPATHSPEM /path/to/dir1 -prepend-path\tFOOPATH /path/to/dir1 -prepend-path\tFOOPATHCB /path/to/dir1 -prepend-path\tFOOPATHEM {} /path/to/dir1 -prepend-path\tFOOPATHWC /path/to/dir1" +setenv\t\tFOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 +setenv\t\tFOOPATHCB /path/to/dir1:/path/to/d\\{r2:/path/to/dir3 +setenv\t\tFOOPATHEM :/path/to/dir1:/path/to/dir2:/path/to/dir3 +setenv\t\tFOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} +setenv\t\tFOOPATHSPEM {/path/to/dir1 /path/to/dir2 /path/to/dir3 } +setenv\t\tFOOPATHWC /path/to/dir1:/path/to/d*r2:/path/to/dir3" testouterr_shtomod ALL {} OK $tserr unsetenv_var FOOPATH unsetenv_var FOOPATHEM @@ -370,8 +367,7 @@ append-path\t-d { } FOOPATHDUPSP /path/to/dir3 /path/to:dir4 append-path\t-d { } FOOPATHDUPSPEM /path/to/dir3 {} append-path\tFOOPATHDUP /path/to/dir3 {/path/to dir4} append-path\tFOOPATHDUPEM /path/to/dir3 {} -append-path\tFOOPATHDUPMIX /path/to/dir3 {} -prepend-path\t-d { } FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1" +setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr # ambiguous prior value @@ -409,13 +405,12 @@ setenv_var FOOPATHDUPMIX "/path/to/dir1 /path/to/dir2" setenv_var FOOPATHDUPSP {/path/to:dir4} setenv_var FOOPATHDUPSPEM {/path/to/dir3 } set tserr "#%Module -append-path\t-d { } FOOPATHDUPMIX /path/to/dir1:/path/to/dir3:/path/to/dir3: append-path\t-d { } FOOPATHDUPSP /path/to/dir3 append-path\tFOOPATHDUP /path/to/dir2 /path/to/dir3 {/path/to dir4} prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir2 prepend-path\tFOOPATHDUPEM /path/to/dir2 -prepend-path\tFOOPATHDUPMIX /path/to/dir1" +setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr unsetenv_var TESTSUITE_SHTOMOD_PATHDUP From 2728c705a9b18640f8e024a954fa1262f1b90b5e Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Thu, 23 Jul 2026 09:03:14 +0200 Subject: [PATCH 2/5] ts: run sh-to-mod/source-sh tests with both path_entry_reorder values Wrap the test bodies of 310-sh-to-mod.exp, 311-eval-sh-to-mod.exp and 400-source-sh.exp in a loop over path_entry_reorder 0 and 1, so both configurations get full coverage instead of only the default one. Each loop iteration resets the environment and loaded module state accumulated by the previous iteration, so both runs start from the same clean baseline. A few path-like values used to test literal curly brace handling needed extra backslash escaping so the whole test body can be parsed as a single Tcl script argument by foreach. Signed-off-by: Xavier Delaruelle --- testsuite/modules.50-cmds/400-source-sh.exp | 40 ++++++++++++--- testsuite/modules.70-maint/310-sh-to-mod.exp | 51 +++++++++++++++---- .../modules.70-maint/311-eval-sh-to-mod.exp | 49 +++++++++++++----- 3 files changed, 111 insertions(+), 29 deletions(-) diff --git a/testsuite/modules.50-cmds/400-source-sh.exp b/testsuite/modules.50-cmds/400-source-sh.exp index e4e245d31..ed47122da 100644 --- a/testsuite/modules.50-cmds/400-source-sh.exp +++ b/testsuite/modules.50-cmds/400-source-sh.exp @@ -23,13 +23,39 @@ set mp $modpath.2 set mpre [regsub -all "\(\[.+?\]\)" $mp {\\\1}] +foreach path_entry_reorder {0 1} { + +setenv_var MODULES_PATH_ENTRY_REORDER $path_entry_reorder + +# reset state accumulated by a previous run through this loop, so each +# path_entry_reorder value is tested from the same clean starting point +foreach var [array names env -glob FOO*] { + unsetenv_var $var +} +foreach var [array names env -glob __MODULES_*] { + unsetenv_var $var +} +unsetenv_var TESTSUITE_SHTOMOD_NOVAR +unsetenv_var TESTSUITE_SHTOMOD_NOPATH +unsetenv_var TESTSUITE_SHTOMOD_NOFUNC +unsetenv_var TESTSUITE_SHTOMOD_NOALIAS +unsetenv_var TESTSUITE_SHTOMOD_NOCOMP +unsetenv_var TESTSUITE_SHTOMOD_NOCD +unsetenv_var TESTSUITE_SHTOMOD_PATHDUP +unsetenv_var TESTSUITE_SHTOMOD_MODULE +unsetenv_var TESTSUITE_SHTOMOD_UNSETALFUNCCOMP +unsetenv_var TESTSUITE_SHTOMOD_FUZZYOUT1 +unsetenv_var TESTSUITE_SOURCESH_ESCCHAR +unsetenv_var MODULES_SET_SHELL_STARTUP +unsetenv_var MODULES_CMD +unsetenv_loaded_module + # setup specific environment setenv_path_var MODULEPATH $mp setenv_var TESTSUITE_SHTOMOD_PATHDUP 1 setenv_var TESTSUITE_SHTOMOD_NOCOMP 1 -setenv_var MODULES_PATH_ENTRY_REORDER 0 # # load and unload tests @@ -527,7 +553,7 @@ $mp/source-sh/5.0: chdir $mp prepend-path FOOPATH /path/to/dir1 /path/to/dir2 /path/to/dir3 -prepend-path FOOPATHCB /path/to/dir1 /path/to/d{r2 /path/to/dir3 +prepend-path FOOPATHCB /path/to/dir1 /path/to/d\{r2 /path/to/dir3 prepend-path FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir3 {/path/to dir4} prepend-path FOOPATHDUPEM {} /path/to/dir1 /path/to/dir2 /path/to/dir3 prepend-path FOOPATHDUPMIX {} /path/to/dir1 {/path/to/dir1 /path/to/dir2 /path/to/dir1} /path/to/dir3 @@ -552,7 +578,7 @@ set-function\tfuncsp { set-function\tfuncwc { echo sou*sh} setenv FOO value -setenv FOOCB va{ue +setenv FOOCB va\{ue setenv FOOEM {} setenv FOOPATHDUPSPEM {/path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to/dir3 } setenv FOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} @@ -592,7 +618,7 @@ $mp/source-sh/5.1: chdir $mp prepend-path FOOPATH /path/to/dir1 /path/to/dir2 /path/to/dir3 -prepend-path FOOPATHCB /path/to/dir1 /path/to/d{r2 /path/to/dir3 +prepend-path FOOPATHCB /path/to/dir1 /path/to/d\{r2 /path/to/dir3 prepend-path FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir3 {/path/to dir4} prepend-path FOOPATHDUPEM {} /path/to/dir1 /path/to/dir2 /path/to/dir3 prepend-path FOOPATHDUPMIX {} /path/to/dir1 {/path/to/dir1 /path/to/dir2 /path/to/dir1} /path/to/dir3 @@ -619,7 +645,7 @@ set-function\tfuncwc { setenv FOO value setenv FOOARG1 arg1 setenv FOOARG2 arg2 -setenv FOOCB va{ue +setenv FOOCB va\{ue setenv FOOEM {} setenv FOOPATHDUPSPEM {/path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to/dir3 } setenv FOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} @@ -1002,7 +1028,7 @@ set tserr_disp3 "--------------------------------------------------------------- $mp/source-sh/5.0: setenv FOO value -setenv FOOCB va{ue +setenv FOOCB va\{ue setenv FOOEM {} setenv FOOSP {value } setenv FOOWC va*ue @@ -1968,6 +1994,8 @@ unsetenv_var TESTSUITE_SHTOMOD_UNSETALFUNCCOMP send_user "\tSkip tests relying on an excepted siteconfig file installed\n" } +} + # # Cleanup diff --git a/testsuite/modules.70-maint/310-sh-to-mod.exp b/testsuite/modules.70-maint/310-sh-to-mod.exp index 251a59fc6..801cb34af 100644 --- a/testsuite/modules.70-maint/310-sh-to-mod.exp +++ b/testsuite/modules.70-maint/310-sh-to-mod.exp @@ -147,7 +147,7 @@ if {$install_setbinpath eq {y} && $install_bindir ni [split $::env(PATH) :]} { } } set tsvar "setenv\t\tFOO value -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} setenv\t\tFOOPATHSPEM {/path/to/dir1 /path/to/dir2 /path/to/dir3 } @@ -271,6 +271,35 @@ complete\tfish othercmd {--short-option 'V' --description 'Command version'}" set tscwd "chdir\t\t$env(TESTSUITEDIR)/modulefiles.2" +# +# The tests +# + +foreach path_entry_reorder {0 1} { + +setenv_var MODULES_PATH_ENTRY_REORDER $path_entry_reorder + +# reset state accumulated by a previous run through this loop, so each +# path_entry_reorder value is tested from the same clean starting point +foreach var [array names env -glob FOO*] { + unsetenv_var $var +} +unsetenv_var TESTSUITE_SHTOMOD_NOVAR +unsetenv_var TESTSUITE_SHTOMOD_NOPATH +unsetenv_var TESTSUITE_SHTOMOD_NOFUNC +unsetenv_var TESTSUITE_SHTOMOD_NOALIAS +unsetenv_var TESTSUITE_SHTOMOD_NOCOMP +unsetenv_var TESTSUITE_SHTOMOD_NOCD +unsetenv_var TESTSUITE_SHTOMOD_SHELLVAR +unsetenv_var TESTSUITE_SHTOMOD_PATHDUP +unsetenv_var TESTSUITE_SHTOMOD_MODULE +unsetenv_var MODULES_SET_SHELL_STARTUP +unsetenv_var MODULES_CMD +unsetenv_var MODULES_COLLECTION_TARGET +unsetenv_var testsuite +unsetenv_path_var MODULEPATH +unsetenv_loaded_module + # test unknown shell testouterr_shtomod unk {} ERR "$error_msgs: Shell 'unk' not supported" $testscriptsh @@ -439,7 +468,7 @@ unsetenv_var TESTSUITE_SHTOMOD_SHELLVAR unsetenv_var TESTSUITE_SHTOMOD_NOVAR set tserr_noarg "#%Module setenv\t\tFOO value -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -447,8 +476,8 @@ set tserr "#%Module setenv\t\tFOO value setenv\t\tFOOARG1 val setenv\t\tFOOARG2 {value } -setenv\t\tFOOARG3 val\\{ue -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOARG3 val\\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -490,7 +519,7 @@ setenv\t\tFOOARG1 v'l setenv\t\tFOOARG2 val\\\"e setenv\t\tFOOARG3 {val\\\"e} setenv\t\tFOOARG4 {} -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -534,7 +563,7 @@ setenv\t\tFOOARG1 v'l setenv\t\tFOOARG2 val\\\"e setenv\t\tFOOARG3 {val\\\"e} setenv\t\tFOOARG4 {} -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -579,14 +608,14 @@ setenv_var FOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 setenv_var FOOPATHEM :/path/to/dir1:/path/to/dir2:/path/to/dir3 setenv_var FOOPATHSP "/path/to/dir1 /path/to/dir2 /path/to/dir3" setenv_var FOOPATHSPEM "/path/to/dir1 /path/to/dir2 /path/to/dir3 " -setenv_var FOOPATHCB /path/to/dir1:/path/to/d{r2:/path/to/dir3 +setenv_var FOOPATHCB /path/to/dir1:/path/to/d\{r2:/path/to/dir3 setenv_var FOOPATHWC /path/to/dir1:/path/to/d*r2:/path/to/dir3 testouterr_shtomod ALL {} OK {} setenv_var FOOPATH /path/to/dir2 setenv_var FOOPATHEM /path/to/dir2 setenv_var FOOPATHSP /path/to/dir2 setenv_var FOOPATHSPEM /path/to/dir2 -setenv_var FOOPATHCB /path/to/d{r2 +setenv_var FOOPATHCB /path/to/d\{r2 setenv_var FOOPATHWC /path/to/d*r2 set tserr "#%Module append-path\t-d { } FOOPATHSP /path/to/dir3 @@ -606,14 +635,14 @@ setenv_var FOOPATH "/path/to/dir2:/path" setenv_var FOOPATHEM "/path/to/dir2:/path" setenv_var FOOPATHSP "/path/to/dir2 /path" setenv_var FOOPATHSPEM "/path/to/dir2 /path" -setenv_var FOOPATHCB "/path/to/d{r2:/path" +setenv_var FOOPATHCB "/path/to/d\{r2:/path" setenv_var FOOPATHWC "/path/to/d*r2:/path" # the prepend and append chunks here would use a different delimiter # character ('/' vs ':'): a plain setenv is used instead of the two path # commands, to produce a more consistent value set tserr "#%Module setenv\t\tFOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 -setenv\t\tFOOPATHCB /path/to/dir1:/path/to/d\\{r2:/path/to/dir3 +setenv\t\tFOOPATHCB /path/to/dir1:/path/to/d\\\{r2:/path/to/dir3 setenv\t\tFOOPATHEM :/path/to/dir1:/path/to/dir2:/path/to/dir3 setenv\t\tFOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} setenv\t\tFOOPATHSPEM {/path/to/dir1 /path/to/dir2 /path/to/dir3 } @@ -882,6 +911,8 @@ if {[is_conf_enabled setpythonpath]} { append tserr $extratserr testouterr_shtomod bash {} OK $tserr +} + # # Cleanup diff --git a/testsuite/modules.70-maint/311-eval-sh-to-mod.exp b/testsuite/modules.70-maint/311-eval-sh-to-mod.exp index 42d31fd5f..17c09b98b 100644 --- a/testsuite/modules.70-maint/311-eval-sh-to-mod.exp +++ b/testsuite/modules.70-maint/311-eval-sh-to-mod.exp @@ -20,8 +20,6 @@ # ############################################################################## -setenv_var MODULES_PATH_ENTRY_REORDER 0 - proc testouterr_shtomod {sh cmdline out err {script {}}} { if {$sh eq {ALL}} { set shlist $::shtomod_avail_shells @@ -83,7 +81,7 @@ if {[is_conf_enabled setpythonpath]} { # expected script env changes set tsvarpre "prepend-path\tFOOPATH /path/to/dir1 /path/to/dir2 /path/to/dir3 -prepend-path\tFOOPATHCB /path/to/dir1 /path/to/d\\{r2 /path/to/dir3 +prepend-path\tFOOPATHCB /path/to/dir1 /path/to/d\\\{r2 /path/to/dir3 prepend-path\tFOOPATHEM {} /path/to/dir1 /path/to/dir2 /path/to/dir3 prepend-path\tFOOPATHWC /path/to/dir1 /path/to/d*r2 /path/to/dir3" set tsvarappwpath {} @@ -148,7 +146,7 @@ if {$install_setbinpath eq {y} && $install_bindir ni [split $::env(PATH) :]} { } } set tsvar "setenv\t\tFOO value -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} setenv\t\tFOOPATHSPEM {/path/to/dir1 /path/to/dir2 /path/to/dir3 } @@ -184,6 +182,30 @@ if {[info exists shell_pathname(bash-eval)]} { skip_if_quick_mode +foreach path_entry_reorder {0 1} { + +setenv_var MODULES_PATH_ENTRY_REORDER $path_entry_reorder + +# reset state accumulated by a previous run through this loop, so each +# path_entry_reorder value is tested from the same clean starting point +foreach var [array names env -glob FOO*] { + unsetenv_var $var +} +unsetenv_var TESTSUITE_SHTOMOD_NOVAR +unsetenv_var TESTSUITE_SHTOMOD_NOPATH +unsetenv_var TESTSUITE_SHTOMOD_NOFUNC +unsetenv_var TESTSUITE_SHTOMOD_NOALIAS +unsetenv_var TESTSUITE_SHTOMOD_NOCOMP +unsetenv_var TESTSUITE_SHTOMOD_NOCD +unsetenv_var TESTSUITE_SHTOMOD_PATHDUP +unsetenv_var TESTSUITE_SHTOMOD_MODULE +unsetenv_var MODULES_SET_SHELL_STARTUP +unsetenv_var MODULES_CMD +unsetenv_var MODULES_COLLECTION_TARGET +unsetenv_var testsuite +unsetenv_path_var MODULEPATH +unsetenv_loaded_module + # remove progressively all kind of changes setenv_var TESTSUITE_SHTOMOD_NOVAR 1 setenv_var TESTSUITE_SHTOMOD_NOPATH 1 @@ -211,7 +233,7 @@ testouterr_shtomod ALL {} OK {} unsetenv_var TESTSUITE_SHTOMOD_NOVAR set tserr_noarg "#%Module setenv\t\tFOO value -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -219,8 +241,8 @@ set tserr "#%Module setenv\t\tFOO value setenv\t\tFOOARG1 val setenv\t\tFOOARG2 {value } -setenv\t\tFOOARG3 val\\{ue -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOARG3 val\\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -234,7 +256,7 @@ setenv\t\tFOOARG1 v'l setenv\t\tFOOARG2 val\\\"e setenv\t\tFOOARG3 {val\\\"e} setenv\t\tFOOARG4 {} -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -250,7 +272,7 @@ setenv\t\tFOOARG1 v'l setenv\t\tFOOARG2 val\\\"e setenv\t\tFOOARG3 {val\\\"e} setenv\t\tFOOARG4 {} -setenv\t\tFOOCB va\\{ue +setenv\t\tFOOCB va\\\{ue setenv\t\tFOOEM {} setenv\t\tFOOSP {value } setenv\t\tFOOWC va*ue" @@ -267,14 +289,14 @@ setenv_var FOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 setenv_var FOOPATHEM :/path/to/dir1:/path/to/dir2:/path/to/dir3 setenv_var FOOPATHSP "/path/to/dir1 /path/to/dir2 /path/to/dir3" setenv_var FOOPATHSPEM "/path/to/dir1 /path/to/dir2 /path/to/dir3 " -setenv_var FOOPATHCB /path/to/dir1:/path/to/d{r2:/path/to/dir3 +setenv_var FOOPATHCB /path/to/dir1:/path/to/d\{r2:/path/to/dir3 setenv_var FOOPATHWC /path/to/dir1:/path/to/d*r2:/path/to/dir3 testouterr_shtomod ALL {} OK {} setenv_var FOOPATH /path/to/dir2 setenv_var FOOPATHEM /path/to/dir2 setenv_var FOOPATHSP /path/to/dir2 setenv_var FOOPATHSPEM /path/to/dir2 -setenv_var FOOPATHCB /path/to/d{r2 +setenv_var FOOPATHCB /path/to/d\{r2 setenv_var FOOPATHWC /path/to/d*r2 set tserr "#%Module append-path\t-d { } FOOPATHSP /path/to/dir3 @@ -294,14 +316,14 @@ setenv_var FOOPATH "/path/to/dir2:/path" setenv_var FOOPATHEM "/path/to/dir2:/path" setenv_var FOOPATHSP "/path/to/dir2 /path" setenv_var FOOPATHSPEM "/path/to/dir2 /path" -setenv_var FOOPATHCB "/path/to/d{r2:/path" +setenv_var FOOPATHCB "/path/to/d\{r2:/path" setenv_var FOOPATHWC "/path/to/d*r2:/path" # the prepend and append chunks here would use a different delimiter # character ('/' vs ':'): a plain setenv is used instead of the two path # commands, to produce a more consistent value set tserr "#%Module setenv\t\tFOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 -setenv\t\tFOOPATHCB /path/to/dir1:/path/to/d\\{r2:/path/to/dir3 +setenv\t\tFOOPATHCB /path/to/dir1:/path/to/d\\\{r2:/path/to/dir3 setenv\t\tFOOPATHEM :/path/to/dir1:/path/to/dir2:/path/to/dir3 setenv\t\tFOOPATHSP {/path/to/dir1 /path/to/dir2 /path/to/dir3} setenv\t\tFOOPATHSPEM {/path/to/dir1 /path/to/dir2 /path/to/dir3 } @@ -545,6 +567,7 @@ if {[is_conf_enabled setpythonpath]} { append tserr $extratserr testouterr_shtomod bash-eval {} OK $tserr +} # # Cleanup From 13cbc04110a5b82d353a607c562e084f798f94ca Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Thu, 23 Jul 2026 21:47:20 +0200 Subject: [PATCH 3/5] Preserve genuine path duplicates in source-sh/sh-to-mod output A path entry added by a prepend-path or append-path command generated by source-sh/sh-to-mod could be silently absorbed or relocated by these commands' default de-duplication behavior, or by the path_entry_reorder configuration option, when this entry was already part of the variable value prior script evaluation, appeared several times in the entries being prepended or appended, or appeared in both the prepended and appended entries. Such an entry is genuinely meant to end up at this specific position in the resulting value, so it is no longer de-duplicated away, and the --duplicates option is now added to the corresponding command in these situations. Signed-off-by: Xavier Delaruelle --- NEWS.rst | 10 ++ .../source-shell-script-in-modulefile.rst | 14 +-- tcl/mfcmd.tcl | 98 +++++++++++++++---- testsuite/modules.50-cmds/400-source-sh.exp | 18 ++-- testsuite/modules.70-maint/310-sh-to-mod.exp | 54 +++++----- .../modules.70-maint/311-eval-sh-to-mod.exp | 43 ++++---- 6 files changed, 156 insertions(+), 81 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 31d932df0..e9508bf06 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -142,6 +142,16 @@ Modules 5.7.0 (not yet released) environment variable change that requires both a prepended and an appended part expressed with a different delimiter character: a :mfcmd:`setenv` command is now generated instead in this situation. +* Update the :mfcmd:`source-sh` modulefile command and :subcmd:`sh-to-mod` + sub-command mechanism to no longer de-duplicate a path entry found several + times in the entries it prepends or in the entries it appends, and to add + the ``--duplicates`` option on a generated :mfcmd:`prepend-path` or + :mfcmd:`append-path` command when one of the path entries it adds is + already found in the variable value prior script evaluation, is found + several times in the entries it adds or is found in both the entries it + prepends and the entries it appends, so this entry is not silently + absorbed by these commands' default de-duplication behavior nor relocated + by the :mconfig:`path_entry_reorder` configuration option. .. _5.6 release notes: diff --git a/doc/source/design/source-shell-script-in-modulefile.rst b/doc/source/design/source-shell-script-in-modulefile.rst index 1c14bdcb6..a503f63a0 100644 --- a/doc/source/design/source-shell-script-in-modulefile.rst +++ b/doc/source/design/source-shell-script-in-modulefile.rst @@ -183,14 +183,16 @@ Specification - to separate each output kind and then be able to split them for separate analysis -- De-duplication of path entries is applied for changes on path-like environment variables +- Path entries found in the newly prepended entries or in the newly appended entries for a variable are never de-duplicated: every occurrence is kept and passed on the corresponding ``prepend-path`` or ``append-path`` command - - If the same path entry appears several times in the newly prepended entries for a variable, the first occurrence of this entry is kept others are dropped - - If the same path entry appears several times in the newly appended entries for a variable, the first occurrence of this entry is kept others are dropped - - De-duplication is not applied for path entries: +- The ``--duplicates`` option is added to a ``prepend-path`` or ``append-path`` command when one of the entries it adds: - - appearing in both the new prepended entries and newly appended entries - - appearing in newly prepended entries or newly appended entries and in entries defined prior script evaluation + - is already found in the variable value prior script evaluation + - is found several times in the newly prepended entries or in the newly appended entries + - is found in both the newly prepended entries and the newly appended entries + + - Such an entry is genuinely meant to end up at this specific position in the resulting value + - Without this option, ``prepend-path`` and ``append-path``'s default de-duplication behavior would silently absorb the entry, and the ``path_entry_reorder`` configuration option could relocate it, which would not correctly reproduce the change made by the script - An environment variable equaling to the path separator character (``:``) prior script evaluation is considered as undefined prior script evaluation to avoid misleading analysis diff --git a/tcl/mfcmd.tcl b/tcl/mfcmd.tcl index 524221483..9fa04c93d 100644 --- a/tcl/mfcmd.tcl +++ b/tcl/mfcmd.tcl @@ -1707,36 +1707,94 @@ proc sh-to-mod {elt_ignored_list args} { } else { # content should be prepended if {$doprepend} { - set modcmd [list prepend-path] + # split value: a directory found several times in this + # list is not de-duplicated, as it is genuinely meant to + # be added at each of these positions in the resulting + # value + set prelist [split [string range $varaft($name) 0\ + $idx-2] $predelim] + set preuniq [list] + lappendNoDup preuniq {*}$prelist + set predupbylen [expr {[llength $prelist] !=\ + [llength $preuniq]}] + # an empty element is added + if {![llength $prelist]} { + lappend prelist {} + } + } + # content should be appended + if {$doappend} { + set applist [split [string range $varaft($name)\ + [expr {$idx + [string length $varbef($name)] + 1}]\ + end] $appdelim] + set appuniq [list] + lappendNoDup appuniq {*}$applist + set appdupbylen [expr {[llength $applist] !=\ + [llength $appuniq]}] + if {![llength $applist]} { + lappend applist {} + } + } + + # a directory to add is genuinely meant to end up at this + # specific position in the resulting value, so pass + # --duplicates on the corresponding command to avoid it + # being silently absorbed by prepend-path/append-path's + # default dedup behavior, or relocated by the + # path_entry_reorder configuration option, when this + # directory: + # - is already found in the value the variable had prior + # the script evaluation + # - is found several times in the directory list to add + # for this command + # - is found in both the directory list to prepend and the + # directory list to append + set dupacross 0 + if {$doprepend && $doappend} { + foreach dir $prelist { + if {$dir in $applist} { + set dupacross 1 + break + } + } + } + if {$doprepend} { + set predupopt [list] + if {$dupacross || $predupbylen} { + set predupopt [list --duplicates] + } else { + foreach dir $prelist { + if {$dir in [split $varbef($name) $predelim]} { + set predupopt [list --duplicates] + break + } + } + } + set modcmd [list prepend-path {*}$predupopt] if {$predelim ne $pathsep} { lappend modcmd -d $predelim } lappend modcmd $name - # split value and remove duplicate entries - set vallist [list] - lappendNoDup vallist {*}[split [string range\ - $varaft($name) 0 $idx-2] $predelim] - # an empty element is added - if {![llength $vallist]} { - lappend vallist {} - } - lappend modcontent [list {*}$modcmd {*}$vallist] + lappend modcontent [list {*}$modcmd {*}$prelist] } - # content should be appended if {$doappend} { - set modcmd [list append-path] + set appdupopt [list] + if {$dupacross || $appdupbylen} { + set appdupopt [list --duplicates] + } else { + foreach dir $applist { + if {$dir in [split $varbef($name) $appdelim]} { + set appdupopt [list --duplicates] + break + } + } + } + set modcmd [list append-path {*}$appdupopt] if {$appdelim ne $pathsep} { lappend modcmd -d $appdelim } lappend modcmd $name - set vallist [list] - lappendNoDup vallist {*}[split [string range\ - $varaft($name) [expr {$idx + [string length\ - $varbef($name)] + 1}] end] $appdelim] - if {![llength $vallist]} { - lappend vallist {} - } - lappend modcontent [list {*}$modcmd {*}$vallist] + lappend modcontent [list {*}$modcmd {*}$applist] } } } diff --git a/testsuite/modules.50-cmds/400-source-sh.exp b/testsuite/modules.50-cmds/400-source-sh.exp index ed47122da..57e53b78c 100644 --- a/testsuite/modules.50-cmds/400-source-sh.exp +++ b/testsuite/modules.50-cmds/400-source-sh.exp @@ -228,13 +228,13 @@ set ans [list] lappend ans [list set FOOPATHDUPEM :/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3::/path/to/dir3] lappend ans [list unset __MODULES_SHARE_FOOPATHDUPEM] lappend ans [list set __MODULES_SHARE_FOOPATHDUPMIX ":2:/path/to/dir3:2"] -lappend ans [list set FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1\ /path/to/dir2\ /path/to/dir1:/path/to/dir3] +lappend ans [list set FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1\ /path/to/dir2\ /path/to/dir1:/path/to/dir3:/path/to/dir3:] lappend ans [list set FOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3] lappend ans [list set __MODULES_LMREFRESH source-sh/1:source-sh/2:source-sh/3] lappend ans [list set _LMFILES_ $mp/source-sh/1:$mp/source-sh/2:$mp/source-sh/3] lappend ans [list set LOADEDMODULES source-sh/1:source-sh/2:source-sh/3] lappend ans [list set FOOPATHDUP "/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3:/path/to dir4:/path/to/dir3"] -lappend ans [list set __MODULES_LMSOURCESH source-sh/1\&bash\ testsuite/example/sh-to-mod.sh\|chdir\ $mp\|prepend-path\ FOOPATH\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHCB\ /path/to/dir1\ /path/to/d\\\{r2\ /path/to/dir3\|prepend-path\ FOOPATHDUP\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \{/path/to\ dir4\}\|prepend-path\ FOOPATHDUPEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHDUPMIX\ \{\}\ /path/to/dir1\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir1\}\ /path/to/dir3\|prepend-path\ FOOPATHDUPSP\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to\}\ \{dir4\ /path/to/dir3\}\|prepend-path\ FOOPATHEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHWC\ /path/to/dir1\ /path/to/d\*r2\ /path/to/dir3\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOO\ value\|setenv\ FOOCB\ va\\\{ue\|setenv\ FOOEM\ \{\}\|setenv\ FOOPATHDUPSPEM\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to/dir3\ \}\|setenv\ FOOPATHSP\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\}\|setenv\ FOOPATHSPEM\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \}\|setenv\ FOOSP\ \{value\ \}\|setenv\ FOOWC\ va\*ue:source-sh/2\&sh\ testsuite/example/mini-sh-to-mod.sh\|prepend-path\ FOOPATH\ /path/to/mini\|set-alias\ almini\ \{\}\|setenv\ FOOMINI\ value:source-sh/3\&bash\ testsuite/example/sh-to-mod.sh\|append-path\ FOOPATHDUPMIX\ /path/to/dir3\ \{\}\|chdir\ $mp\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOOPATH\ /path/to/dir1\/path/to/dir2\/path/to/dir3\|setenv\ FOOPATHDUP\ \{/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\/path/to\ dir4\/path/to/dir3\}\|setenv\ FOOPATHDUPEM\ \/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\\/path/to/dir3] +lappend ans [list set __MODULES_LMSOURCESH source-sh/1\&bash\ testsuite/example/sh-to-mod.sh\|chdir\ $mp\|prepend-path\ FOOPATH\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHCB\ /path/to/dir1\ /path/to/d\\\{r2\ /path/to/dir3\|prepend-path\ FOOPATHDUP\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \{/path/to\ dir4\}\|prepend-path\ FOOPATHDUPEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHDUPMIX\ \{\}\ /path/to/dir1\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir1\}\ /path/to/dir3\|prepend-path\ FOOPATHDUPSP\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to\}\ \{dir4\ /path/to/dir3\}\|prepend-path\ FOOPATHEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHWC\ /path/to/dir1\ /path/to/d\*r2\ /path/to/dir3\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOO\ value\|setenv\ FOOCB\ va\\\{ue\|setenv\ FOOEM\ \{\}\|setenv\ FOOPATHDUPSPEM\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to/dir3\ \}\|setenv\ FOOPATHSP\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\}\|setenv\ FOOPATHSPEM\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \}\|setenv\ FOOSP\ \{value\ \}\|setenv\ FOOWC\ va\*ue:source-sh/2\&sh\ testsuite/example/mini-sh-to-mod.sh\|prepend-path\ FOOPATH\ /path/to/mini\|set-alias\ almini\ \{\}\|setenv\ FOOMINI\ value:source-sh/3\&bash\ testsuite/example/sh-to-mod.sh\|append-path\ --duplicates\ FOOPATHDUPMIX\ /path/to/dir3\ \{\}\|chdir\ $mp\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOOPATH\ /path/to/dir1\/path/to/dir2\/path/to/dir3\|setenv\ FOOPATHDUP\ \{/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\/path/to\ dir4\/path/to/dir3\}\|setenv\ FOOPATHDUPEM\ \/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\\/path/to/dir3] lappend ans [list alias alsp {echo f\"o; echo b\\\"r; echo f\'o}] lappend ans [list alias alfoo {echo $(grep "report .Modules " ../../modulecmd.tcl | tr -d \\ 2>/dev/null | awk '{print $3}')}] lappend ans [list alias alcb echo\ f\{o] @@ -258,16 +258,16 @@ setenv_var FOOPATHDUP "/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/ unsetenv_var __MODULES_SHARE_FOOPATHDUPEM unsetenv_var __MODULES_SHARE_FOOPATH unsetenv_var __MODULES_SHARE_FOOPATHDUP -setenv_path_var FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1\ /path/to/dir2\ /path/to/dir1:/path/to/dir3 +setenv_path_var FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1\ /path/to/dir2\ /path/to/dir1:/path/to/dir3:/path/to/dir3: setenv_var FOOPATH /path/to/dir1:/path/to/dir2:/path/to/dir3 setenv_var FOOPATHDUPEM :/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3::/path/to/dir3 -setenv_var __MODULES_LMSOURCESH source-sh/1\&bash\ testsuite/example/sh-to-mod.sh\|chdir\ $mp\|prepend-path\ FOOPATH\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHCB\ /path/to/dir1\ /path/to/d\\\{r2\ /path/to/dir3\|prepend-path\ FOOPATHDUP\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \{/path/to\ dir4\}\|prepend-path\ FOOPATHDUPEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHDUPMIX\ \{\}\ /path/to/dir1\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir1\}\ /path/to/dir3\|prepend-path\ FOOPATHDUPSP\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to\}\ \{dir4\ /path/to/dir3\}\|prepend-path\ FOOPATHEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHWC\ /path/to/dir1\ /path/to/d\*r2\ /path/to/dir3\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOO\ value\|setenv\ FOOCB\ va\\\{ue\|setenv\ FOOEM\ \{\}\|setenv\ FOOPATHDUPSPEM\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to/dir3\ \}\|setenv\ FOOPATHSP\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\}\|setenv\ FOOPATHSPEM\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \}\|setenv\ FOOSP\ \{value\ \}\|setenv\ FOOWC\ va\*ue:source-sh/2\&sh\ testsuite/example/mini-sh-to-mod.sh\|prepend-path\ FOOPATH\ /path/to/mini\|set-alias\ almini\ \{\}\|setenv\ FOOMINI\ value:source-sh/3\&bash\ testsuite/example/sh-to-mod.sh\|append-path\ FOOPATHDUPMIX\ /path/to/dir3\ \{\}\|chdir\ $mp\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOOPATH\ /path/to/dir1\/path/to/dir2\/path/to/dir3\|setenv\ FOOPATHDUP\ \{/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\/path/to\ dir4\/path/to/dir3\}\|setenv\ FOOPATHDUPEM\ \/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\\/path/to/dir3 +setenv_var __MODULES_LMSOURCESH source-sh/1\&bash\ testsuite/example/sh-to-mod.sh\|chdir\ $mp\|prepend-path\ FOOPATH\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHCB\ /path/to/dir1\ /path/to/d\\\{r2\ /path/to/dir3\|prepend-path\ FOOPATHDUP\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \{/path/to\ dir4\}\|prepend-path\ FOOPATHDUPEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHDUPMIX\ \{\}\ /path/to/dir1\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir1\}\ /path/to/dir3\|prepend-path\ FOOPATHDUPSP\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to\}\ \{dir4\ /path/to/dir3\}\|prepend-path\ FOOPATHEM\ \{\}\ /path/to/dir1\ /path/to/dir2\ /path/to/dir3\|prepend-path\ FOOPATHWC\ /path/to/dir1\ /path/to/d\*r2\ /path/to/dir3\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOO\ value\|setenv\ FOOCB\ va\\\{ue\|setenv\ FOOEM\ \{\}\|setenv\ FOOPATHDUPSPEM\ \{/path/to/dir1\ /path/to/dir1\ /path/to/dir2\ /path/to/dir1\ /path/to/dir3\ /path/to/dir3\ \}\|setenv\ FOOPATHSP\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\}\|setenv\ FOOPATHSPEM\ \{/path/to/dir1\ /path/to/dir2\ /path/to/dir3\ \}\|setenv\ FOOSP\ \{value\ \}\|setenv\ FOOWC\ va\*ue:source-sh/2\&sh\ testsuite/example/mini-sh-to-mod.sh\|prepend-path\ FOOPATH\ /path/to/mini\|set-alias\ almini\ \{\}\|setenv\ FOOMINI\ value:source-sh/3\&bash\ testsuite/example/sh-to-mod.sh\|append-path\ --duplicates\ FOOPATHDUPMIX\ /path/to/dir3\ \{\}\|chdir\ $mp\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOOPATH\ /path/to/dir1\/path/to/dir2\/path/to/dir3\|setenv\ FOOPATHDUP\ \{/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\/path/to\ dir4\/path/to/dir3\}\|setenv\ FOOPATHDUPEM\ \/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\\/path/to/dir3 set ans [list] lappend ans [list set _LMFILES_ $mp/source-sh/2:$mp/source-sh/3] lappend ans [list set LOADEDMODULES source-sh/2:source-sh/3] lappend ans [list unset FOOPATHDUP] -lappend ans [list set __MODULES_LMSOURCESH source-sh/2\&sh\ testsuite/example/mini-sh-to-mod.sh\|prepend-path\ FOOPATH\ /path/to/mini\|set-alias\ almini\ \{\}\|setenv\ FOOMINI\ value:source-sh/3\&bash\ testsuite/example/sh-to-mod.sh\|append-path\ FOOPATHDUPMIX\ /path/to/dir3\ \{\}\|chdir\ $mp\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOOPATH\ /path/to/dir1\/path/to/dir2\/path/to/dir3\|setenv\ FOOPATHDUP\ \{/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\/path/to\ dir4\/path/to/dir3\}\|setenv\ FOOPATHDUPEM\ \/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\\/path/to/dir3] +lappend ans [list set __MODULES_LMSOURCESH source-sh/2\&sh\ testsuite/example/mini-sh-to-mod.sh\|prepend-path\ FOOPATH\ /path/to/mini\|set-alias\ almini\ \{\}\|setenv\ FOOMINI\ value:source-sh/3\&bash\ testsuite/example/sh-to-mod.sh\|append-path\ --duplicates\ FOOPATHDUPMIX\ /path/to/dir3\ \{\}\|chdir\ $mp\|set-alias\ alcb\ \{\}\|set-alias\ alem\ \{\}\|set-alias\ alfoo\ \{\}\|set-alias\ alsp\ \{\}\|set-function\ funccb\ \{\}\|set-function\ funcfoo\ \{\}\|set-function\ funcnl\ \{\}\|set-function\ funcsp\ \{\}\|set-function\ funcwc\ \{\}\|setenv\ FOOPATH\ /path/to/dir1\/path/to/dir2\/path/to/dir3\|setenv\ FOOPATHDUP\ \{/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\/path/to\ dir4\/path/to/dir3\}\|setenv\ FOOPATHDUPEM\ \/path/to/dir1\/path/to/dir1\/path/to/dir2\/path/to/dir1\/path/to/dir3\\/path/to/dir3] lappend ans [list unset FOOPATHEM] lappend ans [list unset FOOPATHSP] lappend ans [list unset FOOPATHCB] @@ -393,7 +393,6 @@ testouterr_cmd sh {display source-sh/4.3} ERR $tserr_disp2 set tserr_disp3 "------------------------------------------------------------------- $mp/source-sh/5.0: -append-path FOOPATHDUPMIX /path/to/dir3 {} chdir $mp set-alias\talcb {echo\ f\{o} set-alias\talem {} @@ -414,7 +413,6 @@ set-function\tfuncwc { echo sou*sh} prepend-path FOOPATH /path/to/mini set-alias almini {echo mini} -append-path FOOPATHDUPMIX /path/to/dir3 {} chdir $mp set-alias\talcb {echo\ f\{o} set-alias\talem {} @@ -440,7 +438,6 @@ testouterr_cmd sh {display source-sh/5.0} OK $tserr_disp3 set tserr_disp4 "------------------------------------------------------------------- $mp/source-sh/5.1: -append-path FOOPATHDUPMIX /path/to/dir3 {} chdir $mp set-alias\talcb {echo\ f\{o} set-alias\talem {} @@ -463,7 +460,6 @@ setenv FOOARG1 arg1 setenv FOOARG2 arg2 prepend-path FOOPATH /path/to/mini set-alias almini {echo mini} -append-path FOOPATHDUPMIX /path/to/dir3 {} chdir $mp set-alias\talcb {echo\ f\{o} set-alias\talem {} @@ -588,7 +584,7 @@ setenv FOOWC va*ue prepend-path FOOPATH /path/to/mini set-alias almini {echo mini} setenv FOOMINI value -append-path FOOPATHDUPMIX /path/to/dir3 {} +append-path --duplicates FOOPATHDUPMIX /path/to/dir3 {} chdir $mp set-alias\talcb {echo\ f\{o} set-alias\talem {} @@ -655,7 +651,7 @@ setenv FOOWC va*ue prepend-path FOOPATH /path/to/mini set-alias almini {echo mini} setenv FOOMINI value -append-path FOOPATHDUPMIX /path/to/dir3 {} +append-path --duplicates FOOPATHDUPMIX /path/to/dir3 {} chdir $mp set-alias\talcb {echo\ f\{o} set-alias\talem {} diff --git a/testsuite/modules.70-maint/310-sh-to-mod.exp b/testsuite/modules.70-maint/310-sh-to-mod.exp index 801cb34af..652dae30f 100644 --- a/testsuite/modules.70-maint/310-sh-to-mod.exp +++ b/testsuite/modules.70-maint/310-sh-to-mod.exp @@ -689,16 +689,16 @@ setenv_var FOOPATHDUPMIX /path/to/dir2 setenv_var FOOPATHDUPSP /path/to/dir2 setenv_var FOOPATHDUPSPEM /path/to/dir2 set tserr "#%Module +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir3 /path/to/dir3 {} +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 +append-path\t--duplicates FOOPATHDUPEM /path/to/dir1 /path/to/dir3 {} /path/to/dir3 append-path\t-d { } FOOPATHDUPMIX /path/to/dir1:/path/to/dir3:/path/to/dir3: -append-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir3 /path/to:dir4 -append-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir3 {} -append-path\tFOOPATHDUP /path/to/dir1 /path/to/dir3 {/path/to dir4} -append-path\tFOOPATHDUPEM /path/to/dir1 /path/to/dir3 {} -prepend-path\t-d { } FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1 -prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 -prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 -prepend-path\tFOOPATHDUP /path/to/dir1 -prepend-path\tFOOPATHDUPEM {} /path/to/dir1" +prepend-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUPEM {} /path/to/dir1 /path/to/dir1 +prepend-path\t-d { } FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1" testouterr_shtomod ALL {} OK $tserr # multiple paths as prior value @@ -708,14 +708,14 @@ setenv_var FOOPATHDUPMIX "/path/to/dir2 /path/to/dir1" setenv_var FOOPATHDUPSP "/path/to/dir2 /path/to/dir1" setenv_var FOOPATHDUPSPEM "/path/to/dir2 /path/to/dir1" set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir3 /path/to:dir4 -append-path\t-d { } FOOPATHDUPSPEM /path/to/dir3 {} -append-path\tFOOPATHDUP /path/to/dir3 {/path/to dir4} -append-path\tFOOPATHDUPEM /path/to/dir3 {} -prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 -prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 -prepend-path\tFOOPATHDUP /path/to/dir1 -prepend-path\tFOOPATHDUPEM {} /path/to/dir1 +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir3 /path/to/dir3 {} +append-path\t--duplicates FOOPATHDUP /path/to/dir3 {/path/to dir4} /path/to/dir3 +append-path\t--duplicates FOOPATHDUPEM /path/to/dir3 {} /path/to/dir3 +prepend-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUPEM {} /path/to/dir1 /path/to/dir1 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr @@ -726,8 +726,8 @@ setenv_var FOOPATHDUPMIX : setenv_var FOOPATHDUPSP /path/to/dir1 setenv_var FOOPATHDUPSPEM { } set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir3 /path/to:dir4 -append-path\tFOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir3 {/path/to dir4} +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 prepend-path\t-d 3 FOOPATHDUPSPEM {/path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir} { /path/to/dir} setenv\t\tFOOPATHDUPEM :/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3::/path/to/dir3 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" @@ -740,8 +740,8 @@ setenv_var FOOPATHDUPMIX {} setenv_var FOOPATHDUPSP /path/to/dir1 setenv_var FOOPATHDUPSPEM {} set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir3 /path/to:dir4 -append-path\tFOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir3 {/path/to dir4} +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 setenv\t\tFOOPATHDUPEM :/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3::/path/to/dir3 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:} setenv\t\tFOOPATHDUPSPEM {/path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to/dir3 }" @@ -754,12 +754,12 @@ setenv_var FOOPATHDUPMIX "/path/to/dir1 /path/to/dir2" setenv_var FOOPATHDUPSP {/path/to:dir4} setenv_var FOOPATHDUPSPEM {/path/to/dir3 } set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir3 -append-path\tFOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir3 {/path/to dir4} -append-path\tFOOPATHDUPEM /path/to/dir3 -prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir3 -prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir2 /path/to/dir3 -prepend-path\tFOOPATHDUPEM {} /path/to/dir1 /path/to/dir2 +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir3 +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 +append-path\t--duplicates FOOPATHDUPEM /path/to/dir3 +prepend-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 +prepend-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 +prepend-path\t--duplicates FOOPATHDUPEM {} /path/to/dir1 /path/to/dir1 /path/to/dir2 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr diff --git a/testsuite/modules.70-maint/311-eval-sh-to-mod.exp b/testsuite/modules.70-maint/311-eval-sh-to-mod.exp index 17c09b98b..43a10a412 100644 --- a/testsuite/modules.70-maint/311-eval-sh-to-mod.exp +++ b/testsuite/modules.70-maint/311-eval-sh-to-mod.exp @@ -370,11 +370,15 @@ setenv_var FOOPATHDUPMIX /path/to/dir2 setenv_var FOOPATHDUPSP /path/to/dir2 setenv_var FOOPATHDUPSPEM /path/to/dir2 set tserr "#%Module +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir3 /path/to/dir3 {} +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 +append-path\t--duplicates FOOPATHDUPEM /path/to/dir1 /path/to/dir3 {} /path/to/dir3 append-path\t-d { } FOOPATHDUPMIX /path/to/dir1:/path/to/dir3:/path/to/dir3: -append-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir3 /path/to:dir4 -append-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir3 {} -append-path\tFOOPATHDUP /path/to/dir1 /path/to/dir3 {/path/to dir4} -append-path\tFOOPATHDUPEM /path/to/dir1 /path/to/dir3 {} +prepend-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUPEM {} /path/to/dir1 /path/to/dir1 prepend-path\t-d { } FOOPATHDUPMIX :/path/to/dir1:/path/to/dir1" testouterr_shtomod ALL {} OK $tserr @@ -385,10 +389,14 @@ setenv_var FOOPATHDUPMIX "/path/to/dir2 /path/to/dir1" setenv_var FOOPATHDUPSP "/path/to/dir2 /path/to/dir1" setenv_var FOOPATHDUPSPEM "/path/to/dir2 /path/to/dir1" set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir3 /path/to:dir4 -append-path\t-d { } FOOPATHDUPSPEM /path/to/dir3 {} -append-path\tFOOPATHDUP /path/to/dir3 {/path/to dir4} -append-path\tFOOPATHDUPEM /path/to/dir3 {} +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir3 /path/to/dir3 {} +append-path\t--duplicates FOOPATHDUP /path/to/dir3 {/path/to dir4} /path/to/dir3 +append-path\t--duplicates FOOPATHDUPEM /path/to/dir3 {} /path/to/dir3 +prepend-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir1 +prepend-path\t--duplicates FOOPATHDUPEM {} /path/to/dir1 /path/to/dir1 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr @@ -399,8 +407,8 @@ setenv_var FOOPATHDUPMIX : setenv_var FOOPATHDUPSP /path/to/dir1 setenv_var FOOPATHDUPSPEM { } set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir2 /path/to/dir3 /path/to:dir4 -append-path\tFOOPATHDUP /path/to/dir2 /path/to/dir3 {/path/to dir4} +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 prepend-path\t-d 3 FOOPATHDUPSPEM {/path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir} { /path/to/dir} setenv\t\tFOOPATHDUPEM :/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3::/path/to/dir3 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" @@ -413,8 +421,8 @@ setenv_var FOOPATHDUPMIX {} setenv_var FOOPATHDUPSP /path/to/dir1 setenv_var FOOPATHDUPSPEM {} set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir2 /path/to/dir3 /path/to:dir4 -append-path\tFOOPATHDUP /path/to/dir2 /path/to/dir3 {/path/to dir4} +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to:dir4 /path/to/dir3 +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 setenv\t\tFOOPATHDUPEM :/path/to/dir1:/path/to/dir1:/path/to/dir2:/path/to/dir1:/path/to/dir3::/path/to/dir3 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:} setenv\t\tFOOPATHDUPSPEM {/path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 /path/to/dir3 }" @@ -427,11 +435,12 @@ setenv_var FOOPATHDUPMIX "/path/to/dir1 /path/to/dir2" setenv_var FOOPATHDUPSP {/path/to:dir4} setenv_var FOOPATHDUPSPEM {/path/to/dir3 } set tserr "#%Module -append-path\t-d { } FOOPATHDUPSP /path/to/dir3 -append-path\tFOOPATHDUP /path/to/dir2 /path/to/dir3 {/path/to dir4} -prepend-path\t-d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir2 -prepend-path\t-d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir2 -prepend-path\tFOOPATHDUPEM /path/to/dir2 +append-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir3 +append-path\t--duplicates FOOPATHDUP /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 {/path/to dir4} /path/to/dir3 +append-path\t--duplicates FOOPATHDUPEM /path/to/dir3 +prepend-path\t--duplicates -d { } FOOPATHDUPSP /path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 +prepend-path\t--duplicates -d { } FOOPATHDUPSPEM /path/to/dir1 /path/to/dir1 /path/to/dir2 /path/to/dir1 /path/to/dir3 +prepend-path\t--duplicates FOOPATHDUPEM {} /path/to/dir1 /path/to/dir1 /path/to/dir2 setenv\t\tFOOPATHDUPMIX {:/path/to/dir1:/path/to/dir1 /path/to/dir2 /path/to/dir1:/path/to/dir3:/path/to/dir3:}" testouterr_shtomod ALL {} OK $tserr From 0e3470e74c79ec932e698e7425b1bda9385ee89c Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Thu, 23 Jul 2026 22:17:32 +0200 Subject: [PATCH 4/5] Simplify sh-to-mod prepend/append path command generation The prepend and append branches of the environment variable diff loop in the sh-to-mod procedure had grown into near-duplicate blocks of code for splitting the directory list to add and deciding whether the --duplicates option is needed on the resulting command. Factor this logic out into two helper procedures, shared by both branches: one building the directory list to add, the other assembling the resulting prepend-path or append-path command. No behavior change. Signed-off-by: Xavier Delaruelle --- tcl/mfcmd.tcl | 133 ++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 70 deletions(-) diff --git a/tcl/mfcmd.tcl b/tcl/mfcmd.tcl index 9fa04c93d..86c58676d 100644 --- a/tcl/mfcmd.tcl +++ b/tcl/mfcmd.tcl @@ -1650,6 +1650,54 @@ proc execShAndGetEnv {elt_ignored_list shell script args} { } } +# split the range of a variable value to prepend or append into a +# directory list for sh-to-mod: a directory found several times in this +# list is not de-duplicated, as it is genuinely meant to be added at each +# of these positions in the resulting value. Whether de-duplication would +# have dropped an entry is also reported, to guide the --duplicates +# option decision made in mkPathAddModCmd +proc splitPathAddList {rangeval delim} { + set dirlist [split $rangeval $delim] + set diruniq [list] + lappendNoDup diruniq {*}$dirlist + set dupbylen [expr {[llength $dirlist] != [llength $diruniq]}] + # an empty element is added + if {![llength $dirlist]} { + lappend dirlist {} + } + return [list $dirlist $dupbylen] +} + +# build the prepend-path or append-path modulefile command adding dirlist +# to variable name for sh-to-mod. --duplicates is set on this command +# when one of its entries is genuinely meant to end up at this specific +# position in the resulting value, so it is not silently absorbed by +# prepend-path/append-path's default dedup behavior, nor relocated by the +# path_entry_reorder configuration option: this is the case when this +# entry is already found in befval, was found several times in dirlist +# prior de-duplication (dupbylen), or is also found in the list of +# entries added on the other side of the value (dupacross) +proc mkPathAddModCmd {cmdname dirlist dupbylen dupacross delim pathsep\ + befval name} { + set dupopt [list] + if {$dupacross || $dupbylen} { + set dupopt [list --duplicates] + } else { + foreach dir $dirlist { + if {$dir in [split $befval $delim]} { + set dupopt [list --duplicates] + break + } + } + } + set modcmd [list $cmdname {*}$dupopt] + if {$delim ne $pathsep} { + lappend modcmd -d $delim + } + lappend modcmd $name + return [list {*}$modcmd {*}$dirlist] +} + # execute script with args through shell and convert environment changes into # corresponding modulefile commands proc sh-to-mod {elt_ignored_list args} { @@ -1707,48 +1755,21 @@ proc sh-to-mod {elt_ignored_list args} { } else { # content should be prepended if {$doprepend} { - # split value: a directory found several times in this - # list is not de-duplicated, as it is genuinely meant to - # be added at each of these positions in the resulting - # value - set prelist [split [string range $varaft($name) 0\ - $idx-2] $predelim] - set preuniq [list] - lappendNoDup preuniq {*}$prelist - set predupbylen [expr {[llength $prelist] !=\ - [llength $preuniq]}] - # an empty element is added - if {![llength $prelist]} { - lappend prelist {} - } + lassign [splitPathAddList [string range $varaft($name)\ + 0 $idx-2] $predelim] prelist predupbylen } # content should be appended if {$doappend} { - set applist [split [string range $varaft($name)\ + lassign [splitPathAddList [string range $varaft($name)\ [expr {$idx + [string length $varbef($name)] + 1}]\ - end] $appdelim] - set appuniq [list] - lappendNoDup appuniq {*}$applist - set appdupbylen [expr {[llength $applist] !=\ - [llength $appuniq]}] - if {![llength $applist]} { - lappend applist {} - } + end] $appdelim] applist appdupbylen } - # a directory to add is genuinely meant to end up at this - # specific position in the resulting value, so pass - # --duplicates on the corresponding command to avoid it - # being silently absorbed by prepend-path/append-path's - # default dedup behavior, or relocated by the - # path_entry_reorder configuration option, when this - # directory: - # - is already found in the value the variable had prior - # the script evaluation - # - is found several times in the directory list to add - # for this command - # - is found in both the directory list to prepend and the - # directory list to append + # a directory found in both the prepended and appended + # entries is also genuinely meant to end up at each of + # these positions in the resulting value: this is passed + # on to mkPathAddModCmd along with each side's own + # dupbylen, to decide whether --duplicates should be set set dupacross 0 if {$doprepend && $doappend} { foreach dir $prelist { @@ -1759,42 +1780,14 @@ proc sh-to-mod {elt_ignored_list args} { } } if {$doprepend} { - set predupopt [list] - if {$dupacross || $predupbylen} { - set predupopt [list --duplicates] - } else { - foreach dir $prelist { - if {$dir in [split $varbef($name) $predelim]} { - set predupopt [list --duplicates] - break - } - } - } - set modcmd [list prepend-path {*}$predupopt] - if {$predelim ne $pathsep} { - lappend modcmd -d $predelim - } - lappend modcmd $name - lappend modcontent [list {*}$modcmd {*}$prelist] + lappend modcontent [mkPathAddModCmd prepend-path\ + $prelist $predupbylen $dupacross $predelim $pathsep\ + $varbef($name) $name] } if {$doappend} { - set appdupopt [list] - if {$dupacross || $appdupbylen} { - set appdupopt [list --duplicates] - } else { - foreach dir $applist { - if {$dir in [split $varbef($name) $appdelim]} { - set appdupopt [list --duplicates] - break - } - } - } - set modcmd [list append-path {*}$appdupopt] - if {$appdelim ne $pathsep} { - lappend modcmd -d $appdelim - } - lappend modcmd $name - lappend modcontent [list {*}$modcmd {*}$applist] + lappend modcontent [mkPathAddModCmd append-path\ + $applist $appdupbylen $dupacross $appdelim $pathsep\ + $varbef($name) $name] } } } From 473c3cb85e65e72605b6c9883a8b4e751fbba685 Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Fri, 24 Jul 2026 10:06:47 +0200 Subject: [PATCH 5/5] Further simplify sh-to-mod prepend/append path command generation Merge the two prepend/append branches of the environment variable diff loop in the sh-to-mod procedure into a single flow: both branches now share one directory list, seeded with the de-duplicated prior value then extended with the raw (non-de-duplicated) entries to prepend and to append, and one pass decides whether --duplicates is needed on the resulting commands. This relies on a new helper procedure checking whether a list holds a repeated element. Seeding with the de-duplicated prior value, rather than merging it in afterwards, avoids a repeated entry already found in the prior value on its own from masking a genuine new duplicate. No behavior change. Signed-off-by: Xavier Delaruelle --- tcl/mfcmd.tcl | 161 ++++++++++++++++++-------------------------------- tcl/util.tcl | 7 +++ 2 files changed, 66 insertions(+), 102 deletions(-) diff --git a/tcl/mfcmd.tcl b/tcl/mfcmd.tcl index 86c58676d..8f9797202 100644 --- a/tcl/mfcmd.tcl +++ b/tcl/mfcmd.tcl @@ -1650,54 +1650,6 @@ proc execShAndGetEnv {elt_ignored_list shell script args} { } } -# split the range of a variable value to prepend or append into a -# directory list for sh-to-mod: a directory found several times in this -# list is not de-duplicated, as it is genuinely meant to be added at each -# of these positions in the resulting value. Whether de-duplication would -# have dropped an entry is also reported, to guide the --duplicates -# option decision made in mkPathAddModCmd -proc splitPathAddList {rangeval delim} { - set dirlist [split $rangeval $delim] - set diruniq [list] - lappendNoDup diruniq {*}$dirlist - set dupbylen [expr {[llength $dirlist] != [llength $diruniq]}] - # an empty element is added - if {![llength $dirlist]} { - lappend dirlist {} - } - return [list $dirlist $dupbylen] -} - -# build the prepend-path or append-path modulefile command adding dirlist -# to variable name for sh-to-mod. --duplicates is set on this command -# when one of its entries is genuinely meant to end up at this specific -# position in the resulting value, so it is not silently absorbed by -# prepend-path/append-path's default dedup behavior, nor relocated by the -# path_entry_reorder configuration option: this is the case when this -# entry is already found in befval, was found several times in dirlist -# prior de-duplication (dupbylen), or is also found in the list of -# entries added on the other side of the value (dupacross) -proc mkPathAddModCmd {cmdname dirlist dupbylen dupacross delim pathsep\ - befval name} { - set dupopt [list] - if {$dupacross || $dupbylen} { - set dupopt [list --duplicates] - } else { - foreach dir $dirlist { - if {$dir in [split $befval $delim]} { - set dupopt [list --duplicates] - break - } - } - } - set modcmd [list $cmdname {*}$dupopt] - if {$delim ne $pathsep} { - lappend modcmd -d $delim - } - lappend modcmd $name - return [list {*}$modcmd {*}$dirlist] -} - # execute script with args through shell and convert environment changes into # corresponding modulefile commands proc sh-to-mod {elt_ignored_list args} { @@ -1724,71 +1676,76 @@ proc sh-to-mod {elt_ignored_list args} { foreach name $diff { if {$name ni $ignvarlist && ![string equal -length 10 $name\ __MODULES_]} { + set idx [string first $varbef($name) $varaft($name)] + set doprepend [expr {$idx > 0}] + if {$doprepend} { + # check from the end to get the largest chunk to prepend + set idx [string last $varbef($name) $varaft($name)] + # get delimiter from char found between new and existing value + set predelim [string index $varaft($name) $idx-1] + set delim $predelim + } + set appdelim_idx [expr {$idx + [string length $varbef($name)]}] + set doappend [expr {$appdelim_idx < [string length $varaft($name)]}] + if {$doappend} { + set appdelim [string index $varaft($name) $appdelim_idx] + set delim $appdelim + } # new value is totally different (also consider a bare ':' as a # totally different value to avoid erroneous matches) - if {$varbef($name) eq $pathsep || [set idx [string first\ - $varbef($name) $varaft($name)]] == -1} { + # if content must both be prepended and appended but each side uses a + # different delimiter character, consider new value totally different + if {$varbef($name) eq $pathsep || $idx == -1 || ($doprepend &&\ + $doappend && $predelim ne $appdelim)} { lappend modcontent [list setenv $name $varaft($name)] } else { - set doprepend [expr {$idx > 0}] + set alllist [list] + # de-dup pre-existing list to correctly determine if new dup added + lappendNoDup alllist {*}[split $varbef($name) $delim] + set addmodcmd [list] + # content should be prepended if {$doprepend} { - # check from the end to get the largest chunk to prepend - set idx [string last $varbef($name) $varaft($name)] - # get delimiter from char found between new and existing value - set predelim [string index $varaft($name) $idx-1] + set prelist [split [string range $varaft($name) 0 $idx-2]\ + $delim] + # an empty element is added + if {![llength $prelist]} { + lappend prelist {} + } + lappend alllist {*}$prelist + lappend addmodcmd prepend-path $prelist } - set doappend [expr {($idx + [string length $varbef($name)]) <\ - [string length $varaft($name)]}] + # content should be appended if {$doappend} { - set appdelim [string index $varaft($name) $idx+[string\ - length $varbef($name)]] - } - - # if content must both be prepended and appended but each side - # uses a different delimiter character, the change cannot be - # expressed as a coherent pair of path-manipulation commands, - # since each delimiter implies a different, incompatible split - # of the value: fall back to a plain setenv to correctly - # capture the new value - if {$doprepend && $doappend && $predelim ne $appdelim} { - lappend modcontent [list setenv $name $varaft($name)] - } else { - # content should be prepended - if {$doprepend} { - lassign [splitPathAddList [string range $varaft($name)\ - 0 $idx-2] $predelim] prelist predupbylen - } - # content should be appended - if {$doappend} { - lassign [splitPathAddList [string range $varaft($name)\ - [expr {$idx + [string length $varbef($name)] + 1}]\ - end] $appdelim] applist appdupbylen + set applist [split [string range $varaft($name) [expr\ + {$appdelim_idx + 1}] end] $delim] + # an empty element is added + if {![llength $applist]} { + lappend applist {} } + lappend alllist {*}$applist + lappend addmodcmd append-path $applist + } - # a directory found in both the prepended and appended - # entries is also genuinely meant to end up at each of - # these positions in the resulting value: this is passed - # on to mkPathAddModCmd along with each side's own - # dupbylen, to decide whether --duplicates should be set - set dupacross 0 - if {$doprepend && $doappend} { - foreach dir $prelist { - if {$dir in $applist} { - set dupacross 1 - break - } - } - } - if {$doprepend} { - lappend modcontent [mkPathAddModCmd prepend-path\ - $prelist $predupbylen $dupacross $predelim $pathsep\ - $varbef($name) $name] + # if a directory is found several times in prepended or appended + # list, or across both list, or already in pre-existing value: + # should not be de-duplicated by prepend-path/append-path's + # default behavior, nor relocated by the path_entry_reorder + # configuration option. a plain membership test (rather than + # merging pre-existing value into alllist) is required here, as + # merging would let lappendNoDup silently skip an entry already + # in alllist, hiding the very overlap this check looks for + set isdup [isDupInList $alllist] + + foreach {cmd addlist} $addmodcmd { + set addcmd [list $cmd] + if {$isdup} { + lappend addcmd --duplicates } - if {$doappend} { - lappend modcontent [mkPathAddModCmd append-path\ - $applist $appdupbylen $dupacross $appdelim $pathsep\ - $varbef($name) $name] + if {$delim ne $pathsep} { + lappend addcmd -d $delim } + lappend addcmd $name {*}$addlist + lappend modcontent $addcmd } } } diff --git a/tcl/util.tcl b/tcl/util.tcl index b636506f6..03873e530 100644 --- a/tcl/util.tcl +++ b/tcl/util.tcl @@ -322,6 +322,13 @@ proc getDiffBetweenList {list1 list2} { return [list $res1 $res2] } +# returns if at least one element in list is present several times +proc isDupInList {arg_list} { + ##nagelfar ignore #2 Unknown variable + lappendNoDup uniq_list {*}$arg_list + return [expr {[llength $arg_list] != [llength $uniq_list]}] +} + # return intersection of all lists: elements present in every list proc getIntersectBetweenList {args} { foreach lst $args {