diff --git a/INSTALL.rst b/INSTALL.rst index 9322b9d1e..63c3a4972 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -1723,6 +1723,9 @@ installation. | | | :envvar:`MODULES_PAGER`, | | | | | | :option:`--paginate`, :option:`--no-pager` | | | +-----------------------------------+----------------------------------------------+----------------------------------------------+--------------+-----------+ +| :mconfig:`path_entry_reorder` | ``0`` | :instopt:`--enable-path-entry-reorder`, | | | +| | | :envvar:`MODULES_PATH_ENTRY_REORDER` | | | ++-----------------------------------+----------------------------------------------+----------------------------------------------+--------------+-----------+ | :mconfig:`protected_envvars` | *Unset by default* | :envvar:`MODULES_PROTECTED_ENVVARS` | | | +-----------------------------------+----------------------------------------------+----------------------------------------------+--------------+-----------+ | :mconfig:`quarantine_support` | ``0`` | :instopt:`--enable-quarantine-support`, | X | | diff --git a/Makefile b/Makefile index 93af6cbec..abc2dca3e 100644 --- a/Makefile +++ b/Makefile @@ -395,6 +395,12 @@ else setwa277 := 0 endif +ifeq ($(pathentryreorder),y) + setpathentryreorder := 1 +else + setpathentryreorder := 0 +endif + ifneq ($(tcllinteropts),) tcllintercmd := $(tcllinter) $(tcllinteropts) else @@ -443,6 +449,7 @@ sed -e 's|@prefix@|$(prefix)|g' \ -e 's|@sourcecache@|$(setsourcecache)|g' \ -e 's|@searchmatch@|$(searchmatch)|g' \ -e 's|@wa277@|$(setwa277)|g' \ + -e 's|@pathentryreorder@|$(setpathentryreorder)|g' \ -e 's|@icase@|$(icase)|g' \ -e 's|@nearlyforbiddendays@|$(nearlyforbiddendays)|g' \ -e 's|@tagabbrev@|$(tagabbrev)|g' \ diff --git a/Makefile.inc.in b/Makefile.inc.in index e9ad51750..aac1ab3ca 100644 --- a/Makefile.inc.in +++ b/Makefile.inc.in @@ -158,6 +158,9 @@ variantshortcut := @variantshortcut@ # editor editor := @editor@ +# Lmod path order +pathentryreorder := @pathentryreorder@ + # shell completion location bashcompletiondir := @bashcompletiondir@ fishcompletiondir := @fishcompletiondir@ diff --git a/configure b/configure index 005eded75..a0c225ede 100755 --- a/configure +++ b/configure @@ -34,7 +34,7 @@ multilibsupport libdir64 libdir32 versioning silentshdbgsupport \ setshellstartup quarantinesupport autohandling availindepth implicitdefault \ extendeddefault moduleshome initconfin pager pageropts verbosity color \ darkbgcolors lightbgcolors termbg lockedconfigs icase unloadmatchorder \ -searchmatch modulepath loadedmodules quarantinevars wa277 advversspec ml \ +searchmatch modulepath loadedmodules quarantinevars wa277 pathentryreorder advversspec ml \ windowssupport nearlyforbiddendays implicitrequirement tagabbrev \ tagcolorname mcookieversioncheck availoutput availterseoutput listoutput \ listterseoutput editor variantshortcut bashcompletiondir fishcompletiondir \ @@ -79,6 +79,7 @@ extendeddefault=y advversspec=y ml=y wa277=n +pathentryreorder=n loadedmodules= quarantinevars= binsearchpath=/usr/bin:/bin:/usr/local/bin @@ -803,6 +804,9 @@ for arg in "$@"; do --enable-mcookie-version-check*|--disable-mcookie-version-check) # shellcheck disable=SC2034 mcookieversioncheck=$(get_feature_value "$arg") ;; + --enable-path-entry-reorder*|--disable-path-entry-reorder) + # shellcheck disable=SC2034 + pathentryreorder=$(get_feature_value "$arg") ;; --with-bin-search-path=*|--without-bin-search-path) binsearchpath=$(get_package_value "$arg") ;; --with-moduleshome=*|--without-moduleshome) diff --git a/doc/source/changes.rst b/doc/source/changes.rst index 957478acd..40baa77f4 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -1279,6 +1279,8 @@ The following Modules configuration option has been introduced on Modules 5. | 5.6 | :mconfig:`spider_output`, :mconfig:`spider_terse_output`, | | | :mconfig:`spider_indepth`, :mconfig:`require_via` | +------------+-----------------------------------------------------------------+ +| 5.7 | :mconfig:`path_entry_reorder` | ++------------+-----------------------------------------------------------------+ :mconfig:`auto_handling` diff --git a/doc/source/module.rst b/doc/source/module.rst index 70501b680..e63f8041f 100644 --- a/doc/source/module.rst +++ b/doc/source/module.rst @@ -1370,6 +1370,23 @@ Module Sub-Commands sub-command when changing this configuration option from its default value. See :envvar:`MODULES_PAGER` description for details. + .. mconfig:: path_entry_reorder + + Change order of entry in a path-like environment variable, when + :mfcmd:`prepend-path`, :mfcmd:`append-path` or :subcmd:`use` target + a path entry that is already defined in the environment variable. + + Default value is ``0``. It can be changed at installation time with the + :instopt:`--with-path-entry-reorder` option. The + :envvar:`MODULES_PATH_ENTRY_REORDER` environment variable is defined by + :subcmd:`config` sub-command when changing this configuration option from + its default value. See :envvar:`MODULES_PATH_ENTRY_REORDER` description + for details. + + .. only:: html + + .. versionadded:: 5.x + .. mconfig:: protected_envvars Prevents any modification of listed environment variables (colon `:` @@ -5274,6 +5291,35 @@ ENVIRONMENT .. versionchanged:: 5.5 No pager when :file:`modulecmd.tcl` is run for scripting languages +.. envvar:: MODULES_PATH_ENTRY_REORDER + + This environment variable changes the behavior of :mfcmd:`prepend-path`, :mfcmd:`append-path` and :subcmd:`use`. + + If set to ``1``, and one of these commands targets a path entry that already exists in the environment variable, the entry is moved to the beginning or end (depending on the command), unless duplicates are allowed. This is the default behavior in Lmod. + If set to ``0``, the environment variable is not modified when the entry already exists. + + Example: + + .. parsed-literal:: + + :ps:`$` module config path_entry_reorder 0 + :ps:`$` module append-path PATHVAR /foo + :ps:`$` module append-path PATHVAR /bar + :ps:`$` module append-path PATHVAR /foo + :ps:`$` echo $PATHVAR + /foo:/bar + :ps:`$` module config path_entry_reorder 1 + :ps:`$` module append-path PATHVAR /foo + :ps:`$` echo $PATHVAR + /bar:/foo + :ps:`$` module append-path --duplicates PATHVAR /bar + :ps:`$` echo $PATHVAR + /bar:/foo:/bar + + .. only:: html + + .. versionadded:: 5.x + .. envvar:: MODULES_PROTECTED_ENVVARS A colon separated list of environment variable names that should not be diff --git a/init/Makefile b/init/Makefile index 19c51a258..3bf487b03 100644 --- a/init/Makefile +++ b/init/Makefile @@ -136,7 +136,7 @@ comp_lint_opts := -a -i --all --icase comp_modtosh_opts := --auto --no-auto --force -f --icase -i comp_path_opts := -d --delim --duplicates comp_rm_path_opts := -d --delim --index -comp_config_opts := --dump-state --reset abort_on_error advanced_version_spec auto_handling avail_indepth avail_output avail_terse_output cache_buffer_bytes cache_expiry_secs collection_pin_version collection_pin_tag collection_target color colors conflict_unload contact editor extended_default extra_siteconfig hide_auto_loaded home icase ignore_cache ignore_user_rc implicit_default implicit_requirement list_output list_terse_output locked_configs logged_events logger mcookie_check mcookie_version_check ml nearly_forbidden_days pager protected_envvars quarantine_support rcfile redirect_output require_via reset_target_state run_quarantine search_match set_shell_startup shells_with_ksh_fpath silent_shell_debug source_cache spider_indepth spider_output spider_terse_output sticky_purge tag_abbrev tag_color_name tcl_linter term_background term_width unique_name_loaded unload_match_order variant_shortcut verbosity wa_277 +comp_config_opts := --dump-state --reset abort_on_error advanced_version_spec auto_handling avail_indepth avail_output avail_terse_output cache_buffer_bytes cache_expiry_secs collection_pin_version collection_pin_tag collection_target color colors conflict_unload contact editor extended_default extra_siteconfig hide_auto_loaded home icase ignore_cache ignore_user_rc implicit_default implicit_requirement list_output list_terse_output locked_configs logged_events logger mcookie_check mcookie_version_check ml nearly_forbidden_days pager path_entry_reorder protected_envvars quarantine_support rcfile redirect_output require_via reset_target_state run_quarantine search_match set_shell_startup shells_with_ksh_fpath silent_shell_debug source_cache spider_indepth spider_output spider_terse_output sticky_purge tag_abbrev tag_color_name tcl_linter term_background term_width unique_name_loaded unload_match_order variant_shortcut verbosity wa_277 define translate-in-script $(ECHO_GEN) @@ -167,6 +167,7 @@ sed -e 's|@prefix@|$(prefix)|g' \ -e 's|@comp_path_opts@|$(comp_path_opts)|g' \ -e 's|@comp_rm_path_opts@|$(comp_rm_path_opts)|g' \ -e 's|@comp_config_opts@|$(comp_config_opts)|g' \ + -e 's|@comp_path_entry_reorder@|$(comp_path_entry_reorder)|g' \ -e '$(setzshfpathre)' \ -e $$'s|@modulerc@|$(modulerc)|g' \ -e 's|@modulepath@|$(modulepath)|g' \ diff --git a/init/fish_completion b/init/fish_completion index 943429bae..1b0a07a5c 100644 --- a/init/fish_completion +++ b/init/fish_completion @@ -87,7 +87,7 @@ complete -c module -n '__fish_module_use_stashlist' -f -a "(module stashlist --c /Stash collection list\$/d; \ /:\$/d; \ /:ERROR:/d;')" -complete -c module -n '__fish_module_use_config' -f -a "--dump-state --reset abort_on_error advanced_version_spec auto_handling avail_indepth avail_output avail_terse_output cache_buffer_bytes cache_expiry_secs collection_pin_version collection_pin_tag collection_target color colors conflict_unload contact editor extended_default extra_siteconfig hide_auto_loaded home icase ignore_cache ignore_user_rc implicit_default implicit_requirement list_output list_terse_output locked_configs logged_events logger mcookie_check mcookie_version_check ml nearly_forbidden_days pager protected_envvars quarantine_support rcfile redirect_output require_via reset_target_state run_quarantine search_match set_shell_startup shells_with_ksh_fpath silent_shell_debug source_cache spider_indepth spider_output spider_terse_output sticky_purge tag_abbrev tag_color_name tcl_linter term_background term_width unique_name_loaded unload_match_order variant_shortcut verbosity wa_277" +complete -c module -n '__fish_module_use_config' -f -a "--dump-state --reset abort_on_error advanced_version_spec auto_handling avail_indepth avail_output avail_terse_output cache_buffer_bytes cache_expiry_secs collection_pin_version collection_pin_tag collection_target color colors conflict_unload contact editor extended_default extra_siteconfig hide_auto_loaded home icase ignore_cache ignore_user_rc implicit_default implicit_requirement list_output list_terse_output locked_configs logged_events logger mcookie_check mcookie_version_check ml nearly_forbidden_days pager path_entry_reorder protected_envvars quarantine_support rcfile redirect_output require_via reset_target_state run_quarantine search_match set_shell_startup shells_with_ksh_fpath silent_shell_debug source_cache spider_indepth spider_output spider_terse_output sticky_purge tag_abbrev tag_color_name tcl_linter term_background term_width unique_name_loaded unload_match_order variant_shortcut verbosity wa_277" complete -f -n '__fish_module_no_subcommand' -c module -a 'help' --description 'Print this or modulefile(s) help info' complete -f -n '__fish_module_no_subcommand' -c module -a 'avail' --description 'List all or matching available modules' diff --git a/init/zsh-functions/_module.in b/init/zsh-functions/_module.in index 380773e19..397b64afe 100644 --- a/init/zsh-functions/_module.in +++ b/init/zsh-functions/_module.in @@ -378,7 +378,7 @@ _module() { _arguments \ '--dump-state[Report each state value of current Modules execution]' \ '--reset[Unset environment variable relative to configuration key]' \ - '1:configuration key:(abort_on_error advanced_version_spec auto_handling avail_indepth avail_output avail_terse_output cache_buffer_bytes cache_expiry_secs collection_pin_version collection_pin_tag collection_target color colors conflict_unload contact editor extended_default extra_siteconfig hide_auto_loaded home icase ignore_cache ignore_user_rc implicit_default implicit_requirement list_output list_terse_output locked_configs logged_events logger mcookie_check mcookie_version_check ml nearly_forbidden_days pager protected_envvars quarantine_support rcfile redirect_output require_via reset_target_state run_quarantine search_match set_shell_startup shells_with_ksh_fpath silent_shell_debug source_cache spider_indepth spider_output spider_terse_output sticky_purge tag_abbrev tag_color_name tcl_linter term_background term_width unique_name_loaded unload_match_order variant_shortcut verbosity wa_277)' \ + '1:configuration key:(abort_on_error advanced_version_spec auto_handling avail_indepth avail_output avail_terse_output cache_buffer_bytes cache_expiry_secs collection_pin_version collection_pin_tag collection_target color colors conflict_unload contact editor extended_default extra_siteconfig hide_auto_loaded home icase ignore_cache ignore_user_rc implicit_default implicit_requirement list_output list_terse_output locked_configs logged_events logger mcookie_check mcookie_version_check ml nearly_forbidden_days pager path_entry_reorder protected_envvars quarantine_support rcfile redirect_output require_via reset_target_state run_quarantine search_match set_shell_startup shells_with_ksh_fpath silent_shell_debug source_cache spider_indepth spider_output spider_terse_output sticky_purge tag_abbrev tag_color_name tcl_linter term_background term_width unique_name_loaded unload_match_order variant_shortcut verbosity wa_277)' \ && ret=0 ;; (edit) diff --git a/site.exp.in b/site.exp.in index 6d35a6b27..d5fff5e3d 100644 --- a/site.exp.in +++ b/site.exp.in @@ -117,6 +117,8 @@ set install_variantshortcut "@variantshortcut@" set install_editor "@editor@" +set install_pathentryreorder "@pathentryreorder@" + set install_bashcompletiondir "@bashcompletiondir@" set install_fishcompletiondir "@fishcompletiondir@" set install_zshcompletiondir "@zshcompletiondir@" diff --git a/tcl/envmngt.tcl.in b/tcl/envmngt.tcl.in index 30b8b5eb3..e338b2f47 100644 --- a/tcl/envmngt.tcl.in +++ b/tcl/envmngt.tcl.in @@ -1808,27 +1808,43 @@ proc add-path {cmd mode dflbhv args} { set val [get-env $var] foreach dir $path_list { - if {![info exists countarr($dir)] || $allow_dup} { + # remove $dir from path only if path_entry_reorder is true and + # $dir is already in path and duplicates are NOT allowed. + if {[getConf path_entry_reorder] && [info exists countarr($dir)]\ + && ! $allow_dup} { + set mpath_list [split $val $separator] + set mpath_list [lsearch -inline -all -not -exact $mpath_list $dir] + set val [join $mpath_list $separator] + } + # add $dir to beginning or end only if path_entry_reorder is true or + # $dir is NOT in path or duplicates are allowed. + # Please note: if path_entry_reorder is true and duplicates are not + # allowed, $dir is not in path ($val) - either it was not in or it + # had been removed. Hence we have to add it. + if {[getConf path_entry_reorder] || ![info exists countarr($dir)]\ + || $allow_dup} { # ignore env var set empty if no empty entry found in reference # counter array (sometimes var is cleared by setting it empty not # unsetting it) if {$val ne {} || [info exists countarr()]} { set sep [expr {$val eq $separator ? {} : $separator}] set val [expr {$bhv eq {prepend} ? "$dir$sep$val" :\ - "$val$sep$dir"}] + "$val$sep$dir"}] } else { set val $dir } } - if {[info exists countarr($dir)]} { - # do not increase counter if bare separator string is added or if - # reference count is ignored (--ignore-refcount set) unless if - # duplicate mode is enabled (--duplicates set) - if {!$val_set_is_delim && (!$ign_refcount || $allow_dup)} { - incr countarr($dir) - } - } else { + #### ref-counting + # if $dir is NOT in path + # set ref-count 1 + # else + # do NOT increase counter if bare separator string is added or if + # reference count is ignored (--ignore-refcount set) unless if + # duplicate mode is enabled (--duplicates set) + if {![info exists countarr($dir)]} { set countarr($dir) 1 + } elseif {!$val_set_is_delim && (!$ign_refcount || $allow_dup)} { + incr countarr($dir) } } @@ -2046,7 +2062,10 @@ proc getModulesEnvVarGlobList {{loaded_ctx 0}} { return $envvar_glob_list } -# ;;; Local Variables: *** -# ;;; mode:tcl *** -# ;;; End: *** +# ;;; Local Variables: +# ;;; Mode: tcl-mode +# ;;; tcl-indent-level: 3 +# ;;; tcl-continued-indent-level: 3 +# ;;; indent-tabs-mode: nil +# ;;; End: # vim:set tabstop=3 shiftwidth=3 expandtab autoindent: diff --git a/tcl/init.tcl.in b/tcl/init.tcl.in index 1e81e6422..a438a6567 100644 --- a/tcl/init.tcl.in +++ b/tcl/init.tcl.in @@ -122,6 +122,7 @@ array set g_config_defs [list\ nearly_forbidden_days {MODULES_NEARLY_FORBIDDEN_DAYS @nearlyforbiddendays@\ 0 i {0 365} {} {} intbe}\ pager {MODULES_PAGER {@pagercmd@} 0 s}\ + path_entry_reorder {MODULES_PATH_ENTRY_REORDER @pathentryreorder@ 0 b {0 1}}\ protected_envvars {MODULES_PROTECTED_ENVVARS 0 l}\ rcfile {MODULERCFILE 0 l}\ redirect_output {MODULES_REDIRECT_OUTPUT 1 0 b {0 1}}\ diff --git a/tcl/subcmd.tcl.in b/tcl/subcmd.tcl.in index a5c90c9fb..4b2b18ca4 100644 --- a/tcl/subcmd.tcl.in +++ b/tcl/subcmd.tcl.in @@ -3152,7 +3152,10 @@ proc cmdModuleSpider {show_oneperline show_mtime show_filter search_filter\ $search_match $modpath_list {*}$args } -# ;;; Local Variables: *** -# ;;; mode:tcl *** -# ;;; End: *** +# ;;; Local Variables: +# ;;; Mode: tcl-mode +# ;;; tcl-indent-level: 3 +# ;;; tcl-continued-indent-level: 3 +# ;;; indent-tabs-mode: nil +# ;;; End: # vim:set tabstop=3 shiftwidth=3 expandtab autoindent: diff --git a/testsuite/install.00-init/010-environ.exp b/testsuite/install.00-init/010-environ.exp index 528786aec..ce76cb5c6 100644 --- a/testsuite/install.00-init/010-environ.exp +++ b/testsuite/install.00-init/010-environ.exp @@ -194,4 +194,7 @@ catch {unset env(MODULERCFILE)} # setup basic locale for tests set env(LANG) "C" +# ensure that tests doesn't run with Lmod path order +unsetenv_var MODULES_PATH_ENTRY_REORDER + # vim:set tabstop=3 shiftwidth=3 expandtab autoindent: diff --git a/testsuite/modules.00-init/010-environ.exp b/testsuite/modules.00-init/010-environ.exp index db0a2a5a1..42932b45a 100644 --- a/testsuite/modules.00-init/010-environ.exp +++ b/testsuite/modules.00-init/010-environ.exp @@ -188,6 +188,9 @@ catch {unset env(MODULES_COLLECTION_TARGET)} catch {unset env(MODULE_VERSION)} catch {unset env(MODULE_VERSION_STACK)} +# ensure that tests doesn't run with Lmod path order +unsetenv_var MODULES_PATH_ENTRY_REORDER + set env(MODULERCFILE) "$env(TESTSUITEDIR)/etc/empty" set ORIG_MODULERCFILE $env(MODULERCFILE) catch {unset env(MODULESHOME)} diff --git a/testsuite/modules.70-maint/220-config.exp b/testsuite/modules.70-maint/220-config.exp index 6a55b7dc8..2068d0043 100644 --- a/testsuite/modules.70-maint/220-config.exp +++ b/testsuite/modules.70-maint/220-config.exp @@ -93,6 +93,7 @@ array set configdfl [list\ ml [expr {$install_ml eq {y}}]\ nearly_forbidden_days $install_nearlyforbiddendays\ pager "$install_pagercmd"\ + path_entry_reorder [expr {$install_pathentryreorder eq {y}}]\ protected_envvars \ quarantine_support [expr {$install_quarantinesupport eq {y}}]\ rcfile \ @@ -158,6 +159,7 @@ array set configvar [list\ ml MODULES_ML\ nearly_forbidden_days MODULES_NEARLY_FORBIDDEN_DAYS\ pager MODULES_PAGER\ + path_entry_reorder MODULES_PATH_ENTRY_REORDER\ protected_envvars MODULES_PROTECTED_ENVVARS\ quarantine_support MODULES_QUARANTINE_SUPPORT\ rcfile MODULERCFILE\ @@ -213,6 +215,7 @@ array set configvalid [list\ mcookie_version_check {0 1}\ ml {0 1}\ nearly_forbidden_days {0 365}\ + path_entry_reorder {0 1}\ quarantine_support {0 1}\ redirect_output {0 1}\ require_via {0 1}\