Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modules aliases and symbols bash completion #500

Closed
adrien-cotte opened this issue Jun 21, 2023 · 7 comments
Closed

Modules aliases and symbols bash completion #500

adrien-cotte opened this issue Jun 21, 2023 · 7 comments
Labels
Milestone

Comments

@adrien-cotte
Copy link
Contributor

adrien-cotte commented Jun 21, 2023

Describe the bug

There is no bash completion for modules described by module-alias and module-version.

To Reproduce

Let's take these modules:

  • gnu/12 (real module)
  • gnu/stable (symbolic version to gnu/12)
  • gcc -> gnu (alias)

Location and content of any modulerc or modulefile involved:

$ cat path/to/modulepath/.modulerc
#%Module
module-alias gcc gnu
module-version gnu/12 stable

Steps to reproduce the behavior (alias):

$ module avail g <tab>-<tab>
gnu/

Steps to reproduce the behavior (symbols):

$ module avail gnu/ <tab>-<tab>
gnu/12

Expected behavior

Expected behavior for alias:

$ module avail g <tab>-<tab>
gnu/ gcc/ 

Expected behavior for symbols:

$ module avail gnu/ <tab>-<tab>
gnu/12 gnu/stable

Modules version and configuration

$ module --version
Modules Release 5.3.0 (2023-05-14)
$ module config --dump-state
Modules Release 5.3.0 (2023-05-14)

- Config. name ---------.- Value (set by if default overridden) ---------------
advanced_version_spec     1
auto_handling             1
avail_indepth             1
avail_output              modulepath:alias:dirwsym:sym:tag:variantifspec:key
avail_terse_output        modulepath:alias:dirwsym:sym:tag:variantifspec
cache_buffer_bytes        32768
cache_expiry_secs         0
collection_pin_tag        0
collection_pin_version    0
collection_target         <undef>
color                     auto
colors                    hi=1:db=2:tr=2:se=2:er=91:wa=93:me=95:in=94:mp=1;94:di=94:al=96:va=93:sy=95:de=4:cm=92:aL=100:L=90;47:H=2:F=41:nF=43:S=46:sS=44:kL=30;48;5;109
contact                   root@localhost
csh_limit                 4000
editor                    vi
extended_default          1
extra_siteconfig          <undef>
home                      /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR (env-var)
icase                     search
ignore_cache              0
ignore_user_rc            0
ignored_dirs              CVS RCS SCCS .svn .git .SYNC .sos
implicit_default          1
implicit_requirement      1
list_output               header:idx:variant:sym:tag:key
list_terse_output         header
locked_configs            
mcookie_check             always
mcookie_version_check     1
ml                        1
nearly_forbidden_days     14
pager                     /usr/bin/less -eFKRX
protected_envvars         <undef>
quarantine_support        0
rcfile                    <undef>
redirect_output           1
reset_target_state        __init__
run_quarantine            <undef>
search_match              starts_with
set_shell_startup         0
shells_with_ksh_fpath     
silent_shell_debug        0
siteconfig                /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/etc/siteconfig.tcl
tag_abbrev                auto-loaded=aL:loaded=L:hidden=H:hidden-loaded=H:forbidden=F:nearly-forbidden=nF:sticky=S:super-sticky=sS:keep-loaded=kL
tag_color_name            
tcl_ext_lib               /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/lib/libtclenvmodules.so
tcl_linter                nagelfar.tcl
term_background           dark
term_width                0
unload_match_order        returnlast
variant_shortcut          
verbosity                 normal
wa_277                    0

- State name -----------.- Value ----------------------------------------------
always_read_full_file     1
autoinit                  0
clock_seconds             1687340275
cmdline                   /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/libexec/modulecmd.tcl bash config --dump-state
commandname               config
cwd                       /home/acotte/modules-dev/modules-5.3.0
debug_msg_prefix          
domainname                (none)
error_count               0
extra_siteconfig_loaded   0
false_rendered            0
force                     0
hiding_threshold          0
inhibit_errreport         0
inhibit_interp            0
init_error_report         1
is_stderr_tty             1
is_win                    0
kernelversion             #140~18.04.1-Ubuntu SMP Fri Aug 5 11:43:34 UTC 2022
lm_info_cached            0
machine                   x86_64
mode                      
modulefile                {}
modulename                
modulenamevr              
nodename                  UN00306315
os                        Linux
osversion                 5.4.0-124-generic
paginate                  1
path_separator            :
rc_loaded                 /home/acotte/.modulerc
report_format             regular
reportfd                  file4
return_false              0
shell                     bash
shelltype                 sh
siteconfig_loaded         1
specifiedname             
sub1_separator            &
sub2_separator            |
subcmd                    config
subcmd_args               --dump-state
supported_shells          sh bash ksh zsh csh tcsh fish cmd tcl perl python ruby lisp cmake r
tcl_ext_lib_loaded        1
tcl_version               8.6.8
term_columns              142
timer                     0
usergroups                sudo acotte
username                  acotte

- Env. variable --------.- Value ----------------------------------------------
BASH_FUNC__module_raw%%   () {  eval "$(/usr/bin/tclsh '/home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/libexec/modulecmd.tcl' bash "$@")";
 _mlstatus=$?;
 return $_mlstatus
}
BASH_FUNC_module%%        () {  local _mlredir=1;
 if [ -n "${MODULES_REDIRECT_OUTPUT+x}" ]; then
 if [ "$MODULES_REDIRECT_OUTPUT" = '0' ]; then
 _mlredir=0;
 else
 if [ "$MODULES_REDIRECT_OUTPUT" = '1' ]; then
 _mlredir=1;
 fi;
 fi;
 fi;
 case " $@ " in 
 *' --no-redirect '*)
 _mlredir=0
 ;;
 *' --redirect '*)
 _mlredir=1
 ;;
 esac;
 if [ $_mlredir -eq 0 ]; then
 _module_raw "$@";
 else
 _module_raw "$@" 2>&1;
 fi
}
LOADEDMODULES             
MODULEPATH                /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/modulefiles
MODULESHOME               /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR
MODULES_CMD               /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/libexec/modulecmd.tcl
__MODULES_LMINIT          module use --append /home/acotte/modules-dev/modules-5.3.0/INSTALL.DIR/modulefiles
@adrien-cotte
Copy link
Contributor Author

If I load an alias (gcc in my example), is it possible to see it in module list output?
Maybe with a special module config call?

In the completion, should I propose -gnu/12 (the real module) or -gcc (the alias loaded by the user) ?

@adrien-cotte
Copy link
Contributor Author

This minimal patch seems ok for aliases, thx Xavier for the tip:

--- bash_completion.in.ori	2023-06-22 14:07:25.081433304 +0200
+++ bash_completion.in	2023-06-22 14:08:43.997726272 +0200
@@ -20,7 +20,7 @@
     local cur="${1:-}"
     # skip avail call if word currently being completed is an option keyword
     if [ -z "$cur" ] || [ "${cur:0:1}" != '-' ]; then
-        module avail --color=never -s -t -S --no-indepth -o '' "$cur" 2>&1
+        module avail --color=never -s -t -S --no-indepth -o 'alias' "$cur" 2>&1
     fi
 }

Gonna try something not too heavy for symbols.

@adrien-cotte
Copy link
Contributor Author

This patch add bash completion for aliases and symbols:

--- bash_completion.in.ori	2023-06-22 14:07:25.081433304 +0200
+++ bash_completion.in	2023-06-22 16:26:14.382431762 +0200
@@ -20,7 +20,31 @@
     local cur="${1:-}"
     # skip avail call if word currently being completed is an option keyword
     if [ -z "$cur" ] || [ "${cur:0:1}" != '-' ]; then
-        module avail --color=never -s -t -S --no-indepth -o '' "$cur" 2>&1
+        local avail_list=$(module avail --color=never -s -t -S --no-indepth -o 'alias:sym' "$cur" 2>&1)
+        # The following code is quite tricky,
+        # but basically it's necessary for aliases and symbols completion
+        #   1. Remove "(@)" alias symbol
+        #   2. Convert "name/ver(sym1:sym2:symn)" to "name/ver name/sym1 name/sym2 ..."
+	    echo "$avail_list" |
+	        sed 's/(@)//g' |
+	        tr ' ' '\n' |
+	    while IFS= read -r line
+	    do
+	        if [[ "$line" =~ ")" ]]
+	        then
+	            prefix=$(echo "$line" | awk -F '/' '{print $1}')
+	            middle=$(echo "$line" | awk -F '[/(]' '{print $2}')
+	            suffix=$(echo "$line" | awk -F '[/(]' '{print $3}' | tr -d ')')
+	            suffixes=$(echo "$suffix" | tr ':' '\n')
+	            echo "${prefix}/${middle}"
+	            for item in $suffixes
+	            do
+	                echo "${prefix}/${item}"
+	            done
+	        else
+	            echo "$line"
+	        fi
+	    done | tr '\n' ' '; echo
     fi
 }

I gonna open a PR with a more clean code.

@xdelaruelle
Copy link
Member

This minimal patch seems ok for aliases, thx Xavier for the tip:

--- bash_completion.in.ori	2023-06-22 14:07:25.081433304 +0200
+++ bash_completion.in	2023-06-22 14:08:43.997726272 +0200
@@ -20,7 +20,7 @@
     local cur="${1:-}"
     # skip avail call if word currently being completed is an option keyword
     if [ -z "$cur" ] || [ "${cur:0:1}" != '-' ]; then
-        module avail --color=never -s -t -S --no-indepth -o '' "$cur" 2>&1
+        module avail --color=never -s -t -S --no-indepth -o 'alias' "$cur" 2>&1
     fi
 }

Gonna try something not too heavy for symbols.

Good. It should also be fixed for other shells with completion script (tcsh, fish, zsh).

I would suggest to create several PRs, with one to fix alias.

@xdelaruelle
Copy link
Member

This patch add bash completion for aliases and symbols:

--- bash_completion.in.ori	2023-06-22 14:07:25.081433304 +0200
+++ bash_completion.in	2023-06-22 16:26:14.382431762 +0200
@@ -20,7 +20,31 @@
     local cur="${1:-}"
     # skip avail call if word currently being completed is an option keyword
     if [ -z "$cur" ] || [ "${cur:0:1}" != '-' ]; then
-        module avail --color=never -s -t -S --no-indepth -o '' "$cur" 2>&1
+        local avail_list=$(module avail --color=never -s -t -S --no-indepth -o 'alias:sym' "$cur" 2>&1)
+        # The following code is quite tricky,
+        # but basically it's necessary for aliases and symbols completion
+        #   1. Remove "(@)" alias symbol
+        #   2. Convert "name/ver(sym1:sym2:symn)" to "name/ver name/sym1 name/sym2 ..."
+	    echo "$avail_list" |
+	        sed 's/(@)//g' |
+	        tr ' ' '\n' |
+	    while IFS= read -r line
+	    do
+	        if [[ "$line" =~ ")" ]]
+	        then
+	            prefix=$(echo "$line" | awk -F '/' '{print $1}')
+	            middle=$(echo "$line" | awk -F '[/(]' '{print $2}')
+	            suffix=$(echo "$line" | awk -F '[/(]' '{print $3}' | tr -d ')')
+	            suffixes=$(echo "$suffix" | tr ':' '\n')
+	            echo "${prefix}/${middle}"
+	            for item in $suffixes
+	            do
+	                echo "${prefix}/${item}"
+	            done
+	        else
+	            echo "$line"
+	        fi
+	    done | tr '\n' ' '; echo
     fi
 }

I gonna open a PR with a more clean code.

Code should be adapted to only rely on shell syntax and sed. No other external tool should be used (to avoid adding new dependencies).

The easiest solution is, I think, to introduce a new element in output configuration to report symbolic versions individually (rather along their relative modulefile). Otherwise code should be added for bash, tcsh, fish and zsh.

See reportModules, isEltInReport and formatListEltToDisplay procedures in tcl/report.tcl.in.

@xdelaruelle
Copy link
Member

Something like the following patch, introducing the indesym element in avail_output and avail_terse_output config options, should do the job:

diff --git a/tcl/init.tcl.in b/tcl/init.tcl.in
index 0f16eb4c..032e761d 100644
--- a/tcl/init.tcl.in
+++ b/tcl/init.tcl.in
@@ -70,10 +70,10 @@ array set g_config_defs [list\
    auto_handling {MODULES_AUTO_HANDLING @autohandling@ 0 b {0 1}}\
    avail_indepth {MODULES_AVAIL_INDEPTH @availindepth@ 0 b {0 1}}\
    avail_output {MODULES_AVAIL_OUTPUT {@availoutput@} 0 l {modulepath alias\
-      dirwsym sym tag key variant variantifspec} {} {} eltlist}\
+      dirwsym indesym sym tag key variant variantifspec} {} {} eltlist}\
    avail_terse_output {MODULES_AVAIL_TERSE_OUTPUT {@availterseoutput@} 0 l\
-      {modulepath alias dirwsym sym tag key variant variantifspec} {} {}\
-      eltlist}\
+      {modulepath alias dirwsym indesym sym tag key variant variantifspec} {}\
+      {} eltlist}\
    cache_buffer_bytes {MODULES_CACHE_BUFFER_BYTES 32768 0 i {4096 1000000} {}\
       {} intbe}\
    cache_expiry_secs {MODULES_CACHE_EXPIRY_SECS 0 0 i {0 31536000} {} {}\
diff --git a/tcl/report.tcl.in b/tcl/report.tcl.in
index afa0613a..b9dc823c 100644
--- a/tcl/report.tcl.in
+++ b/tcl/report.tcl.in
@@ -1284,7 +1284,11 @@ proc reportModules {search_queries header hsgrkey hstyle show_mtime show_idx\
    }
 
    # elements to include in output
-   set report_sym [isEltInReport sym]
+   if {[set report_indesym [isEltInReport indesym 0]]} {
+      set report_sym 0
+   } else {
+      set report_sym [isEltInReport sym]
+   }
    set report_tag [isEltInReport tag]
    set report_alias [isEltInReport alias]
    # enable variant report if variantifspec configured and some variant is
@@ -1387,6 +1391,15 @@ proc reportModules {search_queries header hsgrkey hstyle show_mtime show_idx\
                   $himatchmap] disp dispsgr displen
             }
          }
+         version {
+            # report symbolic version independently from the module it is
+            # attached to. only done on regular or terse output when 'indesym'
+            # element is in relative output configuration option
+            if {$report_indesym} {
+               lassign [formatListEltToDisplay $elt sy {} {} {} 0 0 {} 0 {}\
+                  {} 0 $himatchmap] disp dispsgr displen
+            }
+         }
       }
       if {$dispsgr ne {}} {
          if {$json} {
@@ -1645,10 +1658,15 @@ proc displayElementList {header sgrkey hstyle one_per_line display_idx\
 # Report an output key to help understand what the SGR used on this output
 # correspond to
 proc displayKey {} {
+   # specific key entry for symbolic version if reported independently
+   set typesym [list {symbolic-version}]
+   if {![isEltInReport indesym 0]} {
+      lappend typesym [sgr se (]<SGR>[sgr se )] 18
+   }
+
    array set skipsgr [list hi 1 db 1 tr 1 se 1 er 1 wa 1 me 1 in 1 cm 1 va 1]
    array set typesgr [list mp modulepath di [list directory <SGR>/ 10] al\
-      module-alias sy [list {symbolic-version} [sgr se (]<SGR>[sgr se )] 18]\
-      de [list {default-version}]]
+      module-alias sy $typesym de [list {default-version}]]
 
    set display_list {}
    set len_list {}

I would like to fix this for 5.3.1, which I plan to release by the end of june (or beginning of july). Let me know if you plan to provide pull-request for these fixes in this timeframe.

@xdelaruelle xdelaruelle added this to the 5.3.1 milestone Jun 25, 2023
@xdelaruelle
Copy link
Member

Looking more in depth into the indesym implementation, it seems other parts of the code need to be updated. I will handle this part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants