jdx / mise

dev tools, env vars, task runner
https://mise.jdx.dev
MIT License
10.07k stars 290 forks source link

env._.source has issues when the sourced script changes #1709

Open egnor opened 8 months ago

egnor commented 8 months ago

Describe the bug When the script referenced by an env._.source field changes, the environment doesn't update, even though the sourced script definitely gets re-executed.

To Reproduce This appears to be order dependent so make sure to follow these steps exactly as so:

$ mkdir mise_bug
$ cd mise_bug
$ cat > .mise.toml
[env]
_.source = "./add_to_env.sh"
ADDED_IN_MISE_TOML = "added-in-mise-toml"
[settings]
experimental = true

(press control-D, then continue:)

$ env | grep added-in
$ cat > add_to_env.sh
export ADDED_IN_SOURCED_FILE="added-in-sourced-file"
echo "In add_to_env.sh: ADDED_IN_SOURCED_FILE=$ADDED_IN_SOURCED_FILE" >&2
export PATH="added-in-sourced-file:$PATH"
echo "In add_to_env.sh: PATH=$PATH" >&2

(control-D again, then:)

$ env | grep added-in
$ cd ..
$ cd mise_bug
$ env | grep added-in

Expected behavior Before add_to_env.sh exists, there should be a "No such file or directory" error. $ADDED_IN_MISE_TOML should be set, but $ADDED_IN_SOURCED_FILE should not, and $PATH should be untouched.

After add_to_env.sh is created, the output from that script ("In add_to_env.sh: ...") should appear, $ADDED_IN_SOURCED_FILE should be set in the shell environment, and $PATH should have a prefix added. Changing out and back into the directory should have no effect.

Actual behavior Indeed, after .mise.toml is created but before add_to_env.sh exists, everything is as expected:

/usr/bin/bash: line 1: /home/egnor/mise_bug/add_to_env.sh: No such file or directory
mise +ADDED_IN_MISE_TOML
$ env | grep added-in
ADDED_IN_MISE_TOML=added-in-mise-toml
/usr/bin/bash: line 1: /home/egnor/mise_bug/add_to_env.sh: No such file or directory

However, after creating add_to_env.sh, things are strange:

In add_to_env.sh: ADDED_IN_SOURCED_FILE=added-in-sourced-file                   
In add_to_env.sh: PATH=added-in-sourced-file:[... the normal PATH ...]
$ env | grep added-in
ADDED_IN_MISE_TOML=added-in-mise-toml

So even though the script is clearly run (per the In add_to_env.sh: ... lines), $ADDED_IN_SOURCED_FILE is not set and $PATH is not modified. Upon changing out and back in, things change a bit:

$ cd ..
$ cd mise_bug
In add_to_env.sh: ADDED_IN_SOURCED_FILE=added-in-sourced-file
In add_to_env.sh: PATH=added-in-sourced-file:[... the normal PATH ...]
mise +ADDED_IN_MISE_TOML +ADDED_IN_SOURCED_FILE
In add_to_env.sh: ADDED_IN_SOURCED_FILE=added-in-sourced-file                   
In add_to_env.sh: PATH=added-in-sourced-file:[... the normal PATH ...]
$ env | grep added-in
ADDED_IN_MISE_TOML=added-in-mise-toml
ADDED_IN_SOURCED_FILE=added-in-sourced-file
In add_to_env.sh: ADDED_IN_SOURCED_FILE=added-in-sourced-file                   
In add_to_env.sh: PATH=added-in-sourced-file:[... the normal PATH ...]

So now the script is being run twice (for some reason) and this time $ADDED_IN_SOURCED_FILE is being set, but $PATH is still not being updated even though the script changes it.

mise doctor output

version: 2024.2.18 linux-x64 (4893e09 2024-02-24)
activated: yes
shims_on_path: no

build_info: 
  Target: x86_64-unknown-linux-musl
  Features: DEFAULT, NATIVE_TLS, OPENSSL
  Built: Sat, 24 Feb 2024 06:33:38 +0000
  Rust Version: rustc 1.76.0 (07dca489a 2024-02-04)
  Profile: release

shell: 
  /bin/zsh
  zsh 5.9 (x86_64-ubuntu-linux-gnu)

dirs: 
  data: ~/.local/share/mise
  config: ~/.config/mise
  cache: ~/.cache/mise
  state: ~/.local/state/mise
  shims: ~/.local/share/mise/shims

config_files: 
  ~/mise_bug/.mise.toml

plugins: 
  bun     (core)
  deno    (core)
  erlang  (core)
  go      (core)
  java    (core)
  node    (core)
  python  (core)
  ruby    (core)

toolset: 

env_vars: 
  MISE_SHELL=zsh

settings: 
  activate_aggressive = false
  all_compile = false
  always_keep_download = false
  always_keep_install = false
  asdf_compat = false
  cargo_binstall = true
  color = true
  disable_default_shorthands = false
  disable_tools = []
  experimental = true
  go_default_packages_file = "~/.default-go-packages"
  go_download_mirror = "https://dl.google.com/go"
  go_repo = "https://github.com/golang/go"
  go_set_gopath = false
  go_set_goroot = true
  go_skip_checksum = false
  jobs = 4
  legacy_version_file = true
  legacy_version_file_disable_tools = []
  node_compile = false
  not_found_auto_install = true
  paranoid = false
  plugin_autoupdate_last_check_duration = "7d"
  python_compile = false
  python_default_packages_file = "/home/egnor/.default-python-packages"
  python_pyenv_repo = "https://github.com/pyenv/pyenv.git"
  raw = false
  trusted_config_paths = []
  quiet = false
  verbose = false
  yes = false
  ci = false
  debug = false
  trace = false
  log_level = "info"
  python_venv_auto_create = false

  [status]
  missing_tools = "if_other_versions_installed"
  show_env = false
  show_tools = false

No problems found

Additional context I believe this also happens if the sourced script is modified to change which variables are exported, not just when it was missing and is created, but I haven't explored all the permutations.

jdx commented 8 months ago

this may be the root cause why the "short circuiting" logic isn't working in https://github.com/jdx/mise/issues/1617. I have not investigated but I suspect the short circuiting logic is still incorrectly calling the env var directives are being executed somewhere.