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

mise exec --cd option doesn't activate tools or env #1843

Closed
joshbode opened this issue Mar 30, 2024 · 3 comments · Fixed by #1848
Closed

mise exec --cd option doesn't activate tools or env #1843

joshbode opened this issue Mar 30, 2024 · 3 comments · Fixed by #1848
Labels
bug Something isn't working

Comments

@joshbode
Copy link
Contributor

joshbode commented Mar 30, 2024

Description
The -C/--cd option doesn't appear to resolve tools or env directives.

To Reproduce
Create a directory with a .mise.toml with the following contents:

$ cat /tmp/foo/.mise.toml
[env]
FOO=123

When inside the target directory, the environment variable activates as expected (I'm using the shell hooks and shims):

$ cd /tmp/foo
$ echo $FOO
123
$ /opt/homebrew/bin/mise -C /tmp/foo exec -- printenv FOO
123

However, when using the option to change directory, the environment variable isn't resolved, even though it definitely appears that the directory is being changed when testing with pwd:

$ pwd
/tmp

$ mise -C /tmp/foo exec -- printenv FOO  # as top-level argument 
$ echo $?
1

$ mise exec -C /tmp/foo -- printenv FOO  # as argument of exec
$ echo $?
1

$ mise -C /tmp/foo exec -- pwd
/tmp/foo

Expected behavior
I expect that tools and env are resolved when using the -C/--cd option.

mise doctor output

$ mise doctor
version: 2024.3.9 macos-arm64 (2024-03-24)
activated: yes
shims_on_path: yes

build_info:
  Target: aarch64-apple-darwin
  Features: DEFAULT, NATIVE_TLS
  Built: Sun, 24 Mar 2024 17:00:58 +0000
  Rust Version: rustc 1.76.0 (07dca489a 2024-02-04) (Homebrew)
  Profile: release

shell:
  /bin/zsh
  zsh 5.9 (x86_64-apple-darwin23.0)

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

config_files:
  ~/.config/mise/config.toml

plugins:
  bun     (core)
  deno    (core)
  erlang  (core)
  go      (core)
  java    (core)
  node    (core)
  poetry  https://github.com/mise-plugins/mise-poetry.git#37df872
  python  (core)
  ruby    (core)
  sops    git@github.com:joshbode/mise-sops.git#7558341

toolset:
  python@3.12.2
  python@3.11.8
  python@3.10.14
  poetry@1.8.2

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 = true
  python_default_packages_file = "/Users/josh/.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
Add any other context about the problem here.

@joshbode joshbode added the bug Something isn't working label Mar 30, 2024
@joshbode
Copy link
Contributor Author

joshbode commented Mar 30, 2024

My current work-around is to use the GNU env command to change the directory when mise is invoked:

$ env -C /tmp/foo/bar mise exec -- printenv FOO
123

note: the built-in macOS /usr/bin/env doesn't support the -C/--chdir option, so you could use a wrapper like this to make it work:

$ cat ~/.local/bin/mise_

#! /bin/sh

# work around broken cd functionality in mise

set -eu

MISE_BIN="/opt/homebrew/bin/mise"  # or wherever it's installed

N=$#
I=0

DONE=0
NAME=""

while [ ${I} -lt ${N} ]; do
  I=$((I + 1))

  ARG=$1
  shift

  if [ ${DONE} = 0 ]; then
    if [ "${ARG}" = "--" ]; then
      DONE=1
    elif [ "${NAME}" = "cd" ]; then
      NAME=""
      cd -- "${ARG}" || exit 1
      continue
    elif [ "${ARG}" = "--cd" ] || [ "${ARG}" = "-C" ]; then
      NAME="cd"
      continue
    fi
  fi

  set -- "$@" "${ARG}"
done

exec "${MISE_BIN}" "$@"

@joshbode
Copy link
Contributor Author

joshbode commented Mar 30, 2024

Additionally, if I create a virtual-environment, it will "activate" as expected when I'm in the target directory, but it will not be picked up from outside the directory with the cd option:

$ cat /tmp/foo/.mise.toml

[tools]
python = "3.12"

[env]
_.python.venv = ".venv"

$ cd /tmp/foo
$ mise trust
$ python -m venv .venv
$ cd /tmp

$ cd /tmp/foo
$ echo $VIRTUAL_ENV
/tmp/foo/.venv
$ mise exec -- printenv VIRTUAL_ENV
/tmp/foo/.venv
$ mise exec -C /tmp/foo -- printenv VIRTUAL_ENV
/tmp/foo/.venv
$ which python
/tmp/foo/.venv/bin/python

$ cd /tmp
$ mise exec -C /tmp/foo -- printenv VIRTUAL_ENV
$ echo $?
1
$ mise exec -C /tmp/foo -- which python
/Users/josh/.local/share/mise/installs/python/3.12/bin/python

note: the env workaround works as I'd expect:

$ env -C /tmp/foo/bar mise exec -- printenv VIRTUAL_ENV
/tmp/foo/.venv
$ env -C /tmp/foo mise exec -- which python
/tmp/foo/.venv/bin/python

A similar result is obtained from the mise env command, so I don't think this is exclusively related to mise exec:

$ mise env -C /tmp/foo -J
{
  "PATH": "/Users/josh/.local/share/mise/installs/python/3.12/bin:..."
}

$ env -C /tmp/foo mise env -J
{
  "PATH": "/tmp/foo/.venv/bin:/Users/josh/.local/share/mise/installs/python/3.12/bin:...",
  "VIRTUAL_ENV": "/tmp/foo/.venv"
}

@joshbode
Copy link
Contributor Author

I'm still learning Rust, but this seems to address the problem by having env::set_current_dir(cd) called before other files are loaded in the all_settings_files loop.

diff --git a/src/config/settings.rs b/src/config/settings.rs
index e5cd4630..ef8b2903 100644
--- a/src/config/settings.rs
+++ b/src/config/settings.rs
@@ -197,13 +197,11 @@ impl Settings {
         if let Some(settings) = SETTINGS.read().unwrap().as_ref() {
             return Ok(settings.clone());
         }
+
         let mut sb = Self::builder()
             .preloaded(CLI_SETTINGS.lock().unwrap().clone().unwrap_or_default())
             .env();
-        for file in Self::all_settings_files() {
-            sb = sb.preloaded(file);
-        }
-        let mut settings = sb.preloaded(DEFAULT_SETTINGS.clone()).load()?;
+        let mut settings = sb.load()?;
         if let Some(cd) = &settings.cd {
             static ORIG_PATH: Lazy<std::io::Result<PathBuf>> = Lazy::new(env::current_dir);
             let mut cd = PathBuf::from(cd);
@@ -212,6 +210,14 @@ impl Settings {
             }
             env::set_current_dir(cd)?;
         }
+
+        sb = Self::builder()
+            .preloaded(CLI_SETTINGS.lock().unwrap().clone().unwrap_or_default())
+            .env();
+        for file in Self::all_settings_files() {
+            sb = sb.preloaded(file);
+        }
+        settings = sb.preloaded(DEFAULT_SETTINGS.clone()).load()?;
         if settings.raw {
             settings.jobs = 1;
         }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant