asdf-community / asdf-direnv

direnv plugin for the asdf version manager
https://github.com/asdf-vm/asdf
Apache License 2.0
554 stars 38 forks source link

unbound variables while loading a plugins exec-env #115

Closed mchristen closed 2 years ago

mchristen commented 2 years ago

I have a .tool-versions file with ruby 2.7.2 in it and after running asdf install direnv reload fails to load ruby with the following error. This also seems to happen to other plugins that export environment variables.

direnv: loading ~/baracus/.envrc
direnv: using asdf
direnv: Creating env file /home/developer/.cache/asdf-direnv/env/190183025-499670833-176628233-2702695381
direnv: loading ~/.cache/asdf-direnv/env/190183025-499670833-176628233-2702695381  
direnv: using asdf direnv 2.30.3     
direnv: using asdf ruby 2.7.2    
direnv: loading ~/.asdf/plugins/ruby/bin/exec-env          
./exec-env:6: RUBYLIB: unbound variable             

If I inspect my cached env file from asdf-direnv 0.1.0 I can see that the last line has export RUBYLIB=$'/home/developer/.asdf/plugins/ruby/rubygems-plugin:/home/developer/.asdf/plugins/ruby/rubygems-plugin' whereas the env file made by asdf-direnv 0.2.0 does not contain that line.

jfly commented 2 years ago

That's interesting. I'm not able to reproduce the issue locally. I checked, and I also have a ~/.asdf/plugins/ruby/bin/exec-env file, and I'm guessing it looks identical to yours:

$ cat ~/.asdf/plugins/ruby/bin/exec-env
#!/usr/bin/env bash

current_script_path=${BASH_SOURCE[0]}
ruby_plugin_dir=$(dirname "$(dirname "$current_script_path")")

if [ "$RUBYLIB" = "" ]; then
  export RUBYLIB="$ruby_plugin_dir/rubygems-plugin"
else
  export RUBYLIB="$ruby_plugin_dir/rubygems-plugin:$RUBYLIB"
fi

export PATH=$install_path/bin:$PATH

Line 6 is this if [ "$RUBYLIB" = "" ]; then, which does look like an unbound variable reference. If I add a set -u to the top of this script, I see the exact same behavior as you.

Wild guess: I wonder if there's something different between your bash and my bash, or their configurations that's causing yours to have bash's nounset behavior always turned on? What do you see if you create and run this dead simple bash script?

$ cat test.sh
#!/usr/bin/env bash

BOUND=42
echo "bound: $BOUND"
echo "unbound: $UNBOUND"
$ chmod +x ./test.sh
$ ./test.sh
bound: 42
unbound:

And for the record, here's what my bash looks like:

$ bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
mchristen commented 2 years ago

This is what I get when I run that script

developer@ip-10-10-251-87:~$ ./test.sh
bound: 42
unbound:
developer@ip-10-10-251-87:~$ cat ./test.sh
#!/usr/bin/env bash

BOUND=42
echo "bound: $BOUND"
echo "unbound: $UNBOUND"

My bash version is:

GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

The base system is Debian 11 and I am using asdf 0.9.0.

If I goto this plugin's directory and checkout the 0.1.0 branch and change nothing else about the system the problem goes away entirely which is why I figured maybe the issue was here.

jfly commented 2 years ago

@mchristen, sorry, without the ability to reproduce this myself, I'm pretty stumped. Could you try running env ASDF_DIRENV_DEBUG=true direnv reload in your project directory and sharing the output? There might be something useful there.

BradenM commented 2 years ago

@jfly @mchristen

Hi. Ran into this issue myself and figured I'd chime in with what I've found.

Same as @mchristen, running direnv allow failed with ./exec-env:6: RUBYLIB: unbound variable after I updated to the recent v2 release.

Some likely key info:

Header of my project-local .envrc:

#!/usr/bin/env bash

use asdf

Header of ~/.config/direnv/direnvrc:


#!/usr/bin/env bash

# ASDF Integration
source "$(asdf direnv hook asdf)"

Header of my ~/.zshrc:

# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
##: init direnv (see: https://github.com/romkatv/powerlevel10k/blob/master/README.md#how-do-i-initialize-direnv-when-using-instant-prompt)
. $HOME/.asdf/asdf.sh
(( ${+commands[direnv]} )) && emulate zsh -c "$(asdf exec direnv export zsh)"
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
(( ${+commands[direnv]} )) && emulate zsh -c "$(asdf exec direnv hook zsh)"

Some notes while trying to determine the problem:

export PGDATA="/tmp/maybe-work"

-> and dummy exports for pghost,pgport,rubylib

use asdf

and while it seemed to have worked for postgres, the ruby plugin would then fail with:
```bash

direnv: loading ~/projects/work/my/project/.envrc
direnv: using asdf
direnv: Creating env file /home/bradenmars/.cache/asdf-direnv/env/2251840191-302452863-543912477-3033906221
direnv: ([/home/bradenmars/.asdf/installs/direnv/2.30.3/bin/direnv export zsh]) is taking a while to execute. Use CTRL-C to give up.
direnv: loading ~/.cache/asdf-direnv/env/2251840191-302452863-543912477-3033906221
direnv: using asdf yq v4.12.2
direnv: using asdf yarn 1.22.17
direnv: using asdf shfmt 3.4.2
direnv: using asdf shellcheck 0.8.0
direnv: using asdf rust 1.54.0
direnv: loading ~/.asdf/plugins/rust/bin/exec-env
direnv: using asdf ruby 3.1.1
direnv: loading ~/.asdf/plugins/ruby/bin/exec-env
./exec-env:12: install_path: unbound variable

Finally, I just gave in and removed postgres and ruby from my ~/.tool-versions file. While this did make it work, it's definitely not a solution :wink:

jfly commented 2 years ago

@BradenM thanks for chimining in! That's good to know that this might have something to do with your ~/.tool-versions file. Unfortunately, I'm still not able to reproduce the issue. Can you try boiling your example down to the smallest example possible that reproduces the issue? I assume yq, yarn, etc aren't actually necessary to reproduce the issue?

For example, here's a simple thing I've tried with a system ruby and a project specific python. It seems fine:

$ cat ~/.tool-versions
direnv 2.30.3
ruby 3.1.1
$ cat .tool-versions
python 3.8.10
$ cat .envrc
use asdf
$ direnv reload
direnv: loading ~/tmp/asdf-direnv-issue-115/.envrc
direnv: using asdf
direnv: Creating env file /home/jeremy/.cache/asdf-direnv/env/3021084817-1069596949-3093830401-3260146122
direnv: loading ~/.cache/asdf-direnv/env/3021084817-1069596949-3093830401-3260146122
direnv: using asdf ruby 3.1.1
direnv: loading ~/.asdf/plugins/ruby/bin/exec-env
direnv: using asdf direnv 2.30.3
direnv: using asdf python 3.8.10
direnv: export +RUBYLIB ~PATH
$ ruby --version
ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux]
$ python --version
Python 3.8.10

Does this work for you?

BradenM commented 2 years ago

@jfly Sure thing!

I have reproduced the issue by taking the following steps:

Here is an asciinema cast I have created of me going through the above steps:

asciicast

(and a direct link if the embed isn't working for you: https://asciinema.org/a/480884)

Some additional system information:

Bash Version
$ bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

zsh Version
$ zsh --version
zsh 5.8.1 (x86_64-pc-linux-gnu)
asdf info
$ asdf info
OS:
Linux braden-desktop 5.16.14-1-MANJARO #1 SMP PREEMPT Fri Mar 11 14:12:18 UTC 2022 x86_64 GNU/Linux

SHELL:
zsh 5.8.1 (x86_64-pc-linux-gnu)

ASDF VERSION:
v0.9.0-7493f40

ASDF ENVIRONMENT VARIABLES:
ASDF_DIR=/home/bradenmars/.asdf

ASDF INSTALLED PLUGINS:
awscli                       https://github.com/MetricMike/asdf-awscli.git main ec4ccdc
aws-iam-authenticator        https://github.com/stefansedich/asdf-aws-iam-authenticator.git master ac2668a
cmctl                        https://github.com/asdf-community/asdf-cmctl.git master c013518
dart                         https://github.com/PatOConnor43/asdf-dart.git master 5afa94b
direnv                       https://github.com/asdf-community/asdf-direnv.git master 3e7578b
eksctl                       https://github.com/elementalvoid/asdf-eksctl.git master 5309e4b
flutter                      https://github.com/oae/asdf-flutter.git master 556a70d
flux2                        https://github.com/tablexi/asdf-flux2.git master 0f987b7
fluxctl                      https://github.com/stefansedich/asdf-fluxctl.git master c2ecce0
git-chglog                   https://github.com/GoodwayGroup/asdf-git-chglog.git main ef79c13
golang                       https://github.com/kennyp/asdf-golang.git master cc8bc47
hadolint                     https://github.com/looztra/asdf-hadolint.git master 69840f7
helm                         https://github.com/Antiarchitect/asdf-helm.git master 87eef5a
helmfile                     https://github.com/feniix/asdf-helmfile.git master 80c93ce
java                         https://github.com/halcyon/asdf-java.git master dc8eb0e
jq                           https://github.com/azmcode/asdf-jq.git master 844d712
kind                         https://github.com/johnlayton/asdf-kind.git master 4b6ed61
kompose                      https://github.com/technikhil314/asdf-kompose.git master 2706fa5
kops                         https://github.com/Antiarchitect/asdf-kops.git master 088bf60
krew                         https://github.com/jimmidyson/asdf-krew.git main bcbe4d9
kubectl                      https://github.com/Banno/asdf-kubectl.git master 11ac5c3
kubectx                      https://gitlab.com/wt0f/asdf-kubectx.git master 8c0b4aa
kubespy                      https://github.com/jfreeland/asdf-kubespy.git main 08a4aba
maven                        https://github.com/halcyon/asdf-maven.git master b30fff9
minikube                     https://github.com/alvarobp/asdf-minikube.git master 8ca7b8d
mongosh                      https://github.com/itspngu/asdf-mongosh.git master 23c5fe0
mysql                        https://github.com/iroddis/asdf-mysql.git master 3aaf756
nodejs                       https://github.com/asdf-vm/asdf-nodejs.git master f9957f3
okteto                       https://github.com/BradenM/asdf-okteto master 34f28d7
please                       https://github.com/asdf-community/asdf-please.git master 99bd59f
pnpm                         https://github.com/jonathanmorley/asdf-pnpm.git master 95752a9
poetry                       https://github.com/asdf-community/asdf-poetry.git master 7ea77b0
postgres                     https://github.com/smashedtoatoms/asdf-postgres.git master ff9e6a6
ruby                         https://github.com/asdf-vm/asdf-ruby.git master 811c824
rust                         https://github.com/code-lever/asdf-rust.git master 0c88f99
shellcheck                   https://github.com/luizm/asdf-shellcheck.git master 31cb328
shfmt                        https://github.com/luizm/asdf-shfmt.git master f893252
sops                         https://github.com/feniix/asdf-sops.git master 954411c
vault                        https://github.com/Banno/asdf-hashicorp.git master aeff16f
yarn                         https://github.com/twuni/asdf-yarn.git main 376c540
yq                           https://github.com/sudermanjr/asdf-yq.git master ee7c63c

direnv toml config
[global]
disable_stdin = true
strict_env = true
skip_dotenv = true

BradenM commented 2 years ago

@jfly Aha!

After looking at my direnv toml config while copying it over to the previous post, the strict_env flag stood out to me...

And what would ya know, disabling strict_env and running direnv reload works perfectly fine!

The above demo works without an issue with the following direnv config:


[global]
disable_stdin = true
strict_env = false
skip_dotenv = true

However, it should be noted, according to the man page for direnv.toml:

[global]
   bash_path
       This allows one to hard-code the position of bash. It maybe be useful to set this to avoid having direnv to fail when PATH is being mutated.

   disable_stdin
       If set to true, stdin is disabled (redirected to /dev/null) during the .envrc evaluation.

   skip_dotenv
       Don't look for .env files, only .envrc files.

   strict_env
       If set to true, the .envrc will be loaded with set -euo pipefail. This option will be the default in the future.

   warn_timeout
       Specify how long to wait before warning the user that the command is taking too long to execute. Defaults to "5s".

       A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".  Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".

strict_env If set to true, the .envrc will be loaded with set -euo pipefail. This option will be the default in the future.

IIRC, I had gone ahead and enabled it back when I setup direnv since its set to become the eventual default.

What are your thoughts on this?

jfly commented 2 years ago

Awesome work! If I enable strict_env = true in my ~/.config/direnv/direnv.toml, I can also reproduce the issue.

IMO, this a bug in asdf-ruby itself. I've sent in this PR upstream: https://github.com/asdf-vm/asdf-ruby/pull/259 to address it.

It looks like asdf-postgres has the same issue, but with 4 variables. Would you like to send in a similar PR to them, @BradenM?

jfly commented 2 years ago

I'm going to go ahead and close this issue, because I don't consider this to an asdf-direnv issue, and fortunately there's a straightforward workaround by turning off direnv's strict mode.

BradenM commented 2 years ago

It looks like asdf-postgres has the same issue, but with 4 variables. Would you like to send in a similar PR to them, @BradenM?

Sure! No problem.

I'm going to go ahead and close this issue, because I don't consider this to an asdf-direnv issue, and fortunately there's a straightforward workaround by turning off direnv's strict mode.

Agreed, the root of the issue(s) lie elsewhere. :+1:

Thanks!