Description
(To be clear, this issue affects performance but results in mise behaving predictably. If we "fix" this it will likely cause bugs, but it would in theory make mise much faster in certain situations)
every time that mise x|run
is called mise will parse all of the tools, config, and do all the resolution to figure out the current environment. That should not be necessary if it was already done and nothing changed. This happens in several ways, but here is one example:
[tasks.a]
run = 'mise run b'
[tasks.b]
run = 'echo b'
if we run mise run a
it will resolve the entire mise environment twice. If the user entered the directory in an activated shell session, then we actually have done it 3 times. This is wasteful but it's actually a little tricky to not do this.
I think there are 2 potential approaches to this:
- reusing PATH and other mise env vars and simply trusting those have not changed—this may or may not work. We may need the resolved config env for some logic inside of
mise x|run
outside of the big things like PATH. - caching the results of a given config/datadir. In theory, if a config file has not changed and
~/.local/share/mise
has not either, we should be able to cache the results of resolving a config.
The first approach, "skipping", might be simple to achieve and low-risk. If we can just detect that the mise env was already loaded and that it cannot have changed (perhaps reusing some of the hook-env early-exit logic), then we could just skip that whole part of mise activation.
These may not be mutually exclusive either. The caching would have benefits for things like moving around directories with an activated session since we would cache each config root (presumably) individually. Even if opening a new directory the global config and parent configs would be cached and we'd only need to load the child. Of course this invites the perennial issues that come along with caching in any software project—but I think in our case we could mostly avoid issues.
IMO the biggest problem likely would be users modifying ~/.local/share/mise/installs
directories. We probably wouldn't want to check every file in each install (because that could be way too many files and because files in there may often get changed in normal operation this would result in not caching when we should). We would probably just check the install root, e.g.: ~/.local/share/mise/installs/python/3.11.0
which mise does touch anytime it installs/updates things.
We would also need to take into account env vars that modify how resolution happens like MISE_PYTHON_VERSION
—though these are far from the only ones. It might be necessary to grab all of MISE_*
and use that as part of the cache key.
We might be able to combine these too. If we had a cache key for a particular config root, we could both cache the results of it but also skip even loading the cache if we know it hasn't changed and the environment is already loaded.