complete-alias icon indicating copy to clipboard operation
complete-alias copied to clipboard

Difficulty with `complete -C` commands

Open mbenson opened this issue 3 years ago • 13 comments

I use certain utility packages to manage multiple versions of a given utility. One such is tfenv to manage Terraform. This sets up my PATH such that the executable file named terraform is symlinked to a script that invokes the appropriate actual instance. Command completion works without issue. I would like to set up an alias, e.g.: alias tfinit='terraform init ... $@' but I find that this gives me errors like: -bash: compgen: warning: -C option may not work as you expect

Is this possible? What can I do to help complete-alias DWIM?

Thanks, Matt

mbenson avatar Oct 06 '21 15:10 mbenson

Is there a minimum working example? I mean, something that can be reproduced exactly?

At least tell me if you are on Linux or Mac, bash version, and show me the output of ls -l terraform and cat terraform?

cykerway avatar Oct 07 '21 14:10 cykerway

Sorry, it didn't occur to me to tell you my OS. :P I'm on MacOS.

 > ls -l `which terraform`
lrwxr-xr-x  1 foo  admin  35 Oct  6 10:20 /usr/local/bin/terraform -> ../Cellar/tfenv/2.2.2/bin/terraform

tfenv's version of terraform can be viewed at https://github.com/tfutils/tfenv/blob/master/bin/terraform .

If you think it would be helpful I could try to create a Dockerfile with my setup, assuming the problem is reproducible in Linux.

Thanks for a cool utility!

mbenson avatar Oct 07 '21 16:10 mbenson

Several points:

  1. You didn't report your bash version. Run bash --version to see if it's 4.4 or higher.
  2. Support for Mac is experimental. It'd be great if you can reproduce the bug on a Linux system.
  3. I wonder if you have pasted the alias body literally, since I don't expect $@ in an alias body.

cykerway avatar Oct 09 '21 20:10 cykerway

  1. GNU bash, version 5.1.8(1)-release (x86_64-apple-darwin20.3.0)
  2. Will attempt
  3. My original, complete, alias was:
f() { terraform init --backend-config="username=REDACTED --backend-config="password=`cat REDACTED_FILE` $@; unset -f f; }; f

Prompted by your comment I simplified to:

terraform init --backend-config="username=REDACTED" --backend-config=password=${REDACTED_VAR}"

...and reran complete -F _complete_alias tfinit. With this I have a bit more error text. The following reflects my typing tfinit and pressing <TAB>:

 tfinit -bash: ((: == 1 : syntax error: operand expected (error token is "== 1 ")
-bash: compgen: warning: -C option may not work as you expect
Terraform has no command named "compgen".

To see all of Terraform's top-level commands, run:
  terraform -help

Additionally I tried moving the init command to the end of the alias, after the ``--backend-config` switch options (and subsequently rerunning the command to set up the completion), but still to no avail.

mbenson avatar Oct 11 '21 14:10 mbenson

Dockerfile to reproduce on Debian 10/Buster:

FROM wolfsoftwareltd/tfenv-debian

ARG CA_VERSION=1.18.0

RUN apt-get update && apt install bash-completion && \
 echo source /etc/profile.d/bash_completion.sh >> .bashrc && \
 curl -L https://github.com/cykerway/complete-alias/archive/refs/tags/${CA_VERSION}.tar.gz | tar zx --strip-components=1 complete-alias-${CA_VERSION}/complete_alias && \
 .tfenv/bin/tfenv install && .tfenv/bin/tfenv use && .tfenv/bin/terraform -install-autocomplete && \
 echo source ./complete_alias >> .bashrc && \
 echo alias tfinit=\'terraform init\' >> .bashrc && \
 echo complete -F _complete_alias tfinit >> .bashrc

mbenson avatar Oct 11 '21 18:10 mbenson

Dockerfile to reproduce:

FROM wolfsoftwareltd/tfenv-debian

ARG CA_VERSION=1.18.0

RUN apt-get update && apt install bash-completion && \
 echo source /etc/profile.d/bash_completion.sh >> .bashrc && \
 curl -L https://github.com/cykerway/complete-alias/archive/refs/tags/${CA_VERSION}.tar.gz | tar zx --strip-components=1 complete-alias-${CA_VERSION}/complete_alias && \
 .tfenv/bin/tfenv install && .tfenv/bin/tfenv use && .tfenv/bin/terraform -install-autocomplete && \
 echo source ./complete_alias >> .bashrc && \
 echo alias tfinit=\'terraform init\' >> .bashrc && \
 echo complete -F _complete_alias tfinit >> .bashrc

Run this container and try to complete tfinit; error is reproduced.

mbenson avatar Oct 15 '21 21:10 mbenson

First of all, I need some minor modifications to successfully reproduce the bug:

FROM wolfsoftwareltd/tfenv-debian

ARG CA_VERSION=1.18.0

RUN apt-get update && apt-get install bash-completion unzip && \
 echo source /etc/profile.d/bash_completion.sh >> .bashrc && \
 curl -L https://github.com/cykerway/complete-alias/archive/refs/tags/${CA_VERSION}.tar.gz | tar zx --strip-components=1 complete-alias-${CA_VERSION}/complete_alias && \
 .anyenv/envs/tfenv/bin/tfenv install && .anyenv/envs/tfenv/bin/tfenv use && .anyenv/envs/tfenv/bin/terraform -install-autocomplete && \
 echo source ./complete_alias >> .bashrc && \
 echo alias tfinit=\'terraform init\' >> .bashrc && \
 echo complete -F _complete_alias tfinit >> .bashrc

Now tab-complete tfinit does give the error you pointed out.

However, I don't think this is an alias problem. To see why, you can try this Dockerfile instead:

FROM wolfsoftwareltd/tfenv-debian

RUN apt-get update && apt-get install bash-completion unzip && \
 echo source /etc/profile.d/bash_completion.sh >> .bashrc && \
 .anyenv/envs/tfenv/bin/tfenv install && .anyenv/envs/tfenv/bin/tfenv use && .anyenv/envs/tfenv/bin/terraform -install-autocomplete

Now tab-complete terraform works as usual, but tab-complete sudo terraform fails:

bash: compgen: warning: -C option may not work as you expect
...

There seems to be some problem when using complete -C with sudo. If you run complete -p terraform then you'd see its completion is done with -C. And as you see, the root cause is not here in complete-alias (because the bug emerges even without aliases). So I'd suggest you pivot to https://github.com/scop/bash-completion and create an issue there and see what they say. You can simply tell them tab-complete terraform is working but sudo terraform is not, with this second Dockerfile. You can then link the issue back here if you want, because this issue would depend on that one.

cykerway avatar Oct 19 '21 14:10 cykerway

Furthermore, terraform is an interesting binary because it knows about auto completion, which can complicate the problem.

Instead, I can give you a simpler example if you decide to report the bug upstream:

complete -C 'echo' foo
sudo foo <tab>

gives the error:

-bash: compgen: warning: -C option may not work as you expect

cykerway avatar Oct 19 '21 14:10 cykerway

I don't think this has anything to do with symlinks. I think the problem happens because of complete -C. The function _command_offset from bash-completion does not handle such commands perfectly.

cykerway avatar Oct 19 '21 14:10 cykerway

Thanks for the in-depth analysis! A question: were you able to determine that sudo is used by tfenv in some way I had not noticed, or are you rather saying that sudo and tfenv/terraform are both susceptible to the same problem with complete -C?

mbenson avatar Oct 19 '21 14:10 mbenson

I don't know if tfenv uses sudo or not, but both complete-alias and sudo utilize the same function _command_offset provided by bash-completion. That seems to be the problematic thing here. If this alone doesn't solve the problem, then we need to look at terraform itself.

BTW, I shall create the upstream issue for you. Created as https://github.com/scop/bash-completion/issues/631.

cykerway avatar Oct 19 '21 14:10 cykerway

Was just about to go create it but wanted to look like I had some idea what I was talking about ;) . Thanks again.

mbenson avatar Oct 19 '21 15:10 mbenson

I had a similar issue when I tried to alias terraform to tf. I found a workaround:

alias tf=terraform
complete -C /path/to/terraform tf

In your case, it's a little more complicated:

alias tfinit='terraform init'
complete -C 'COMP_LINE="terraform init${COMP_LINE:6}" COMP_POINT=$((COMP_POINT+8)) terraform' tfinit
# 6 == len('tfinit')
# 8 == len('terraform init') - len('tfinit')

The key is to trick terraform into thinking it's completing terraform init blah blah.

zzJinux avatar Mar 10 '24 09:03 zzJinux