• Stars
    star
    535
  • Rank 82,940 (Top 2 %)
  • Language
    Shell
  • License
    Apache License 2.0
  • Created about 5 years ago
  • Updated 7 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

direnv plugin for the asdf version manager

asdf-direnv

direnv plugin for asdf version manager

Build History

Build history

Motivation (or shims de-motivation)

asdf version resolution is slow which makes every command execution pay that penalty. asdf reshim is needed for finding new executables, and some tools are not happy with their executables being masked by shims.

asdf is a great tool for managing multiple versions of command-line tools. 99% of the time these managed tools work just as expected.

Shims are just tiny wrappers created by asdf that just forward execution to the real versioned executables installed by asdf. This way, asdf has a single shims directory added to your PATH and has no need of mangling the PATH for every installed version.

When you run an asdf-managed command, like node, it will actually execute an asdf-shim, which will determine the node version to activate according to your .tool-versions file.

A downside of this is that every single time you run node asdf will have to determine again which version to use. Even if you haven't changed your .tool-versions file to upgrade the node version to use. And this happens for every shim execution, which could lead to some users experiencing certain slowness while asdf is looking up versions, since it has to traverse directories looking up for a .tool-versions file and probably also legacy version files.

Another inconvenience is that commands installed by these tools can have some problems by the way asdf shims work. For example, if a command tries to find itself by name in PATH (e.g. using which my-command) it will find the asdf shim executable and not the actual executable delegated-to by asdf. This might cause problems if the command tries to use this location as an installation root to find auxiliary files, since shims will mask the real executable.

Also, people frequently ask why is reshim needed. Suppose you used asdf to install a package manager like npm, hex, gem, cargo, etc. Any new binaries installed by these tools won't be available on PATH unless you run asdf reshim. This is because asdf has no way of knowing what the npm install command does, and it's until asdf reshim that it will figure out new executables are available and will create shims for them accordingly.

And finally, some packages come not only with language-specific commands, but with tons of system tools that will shadow those already installed on your system. While this may be desirable while the language is in use, having it installed and not activated leaves dead shims all over the place.

Solution

Perform asdf version resolution only once and defer environment loading to direnv.

All these previously mentioned issues can be solved by using asdf along with the direnv tool.

Just like asdf is a tools manager, direnv is an environment-variables manager. It can update your shell env upon directory change and clean it up when you leave that directory.

This asdf-direnv plugin lets you install direnv and also provides a tiny script to integrate both. Allowing direnv to manage any variables exposed by asdf tools, primarily the PATH environment, but also any other variable exposed by your plugin (e.g. MIX_HOME exposed by the asdf-elixir plugin).

This way, running node will not invoke the asdf-shim but the real asdf-managed executable in PATH. Which will improve speed since version resolution is out of the way and made only once by direnv upon entering your project directory. Commands trying to find themselves in PATH will find their expected location. Also, no more reshim needed upon npm install.

Prerequirements

  • Make sure you have the required dependencies installed:
    • curl
    • git

Usage

Setup

Install this plugin and run the setup command for all of your preferred shells bash/fish/zsh.

asdf plugin-add direnv
asdf direnv setup --shell bash --version latest

If you already have a direnv installation, you can specify --version system.

Otherwise this plugin can install it for you. Specify either --version latest or a direnv release as shown by asdf list-all direnv.

The setup will hint which files were modified, you might want to review its changes. After setup, close and open your terminal.

Configuration

By default asdf-direnv will fail if a plugin is not installed, but is possible to change this using the environment variable ASDF_DIRENV_IGNORE_MISSING_PLUGINS=1

Per-Project Environments

Once direnv is hooked into your system, use the asdf direnv local command on your project root directory to update your environment.

asdf direnv local [<tool> <version>]...

Temporary environments for one-shot commands

Some times you just want to execute a one-shot commmand under certain environment without creating/modifying .envrc and .tool-versions files on your project directory. In those cases, you might want to try using asdf direnv shell.

# Enter a new shell having python and node
$ asdf direnv shell python 3.8.10 nodejs 14.18.2

# Just execute a npx command under some node version.
$ asdf direnv shell nodejs 14.18.2 -- npx create-react-app

Updating

Updating this plugin is the same as any asdf plugin:

asdf plugin update direnv

Updating the version of direnv you use depends on which installation method you've chosen:

  • system: Nothing special required here, whenever your system package manager updates direnv, this plugin will use the updated version.

  • latest or <direnv-release-version>: Re-run asdf direnv setup --version latest --shell ... to update to the latest version of direnv.

Cached environment

To speed up things a lot, this plugin creates direnv envrc files that contain your tools environment. They are created automatically whenever your .envrc or your .tool-versions files change.

Cached environment files can be found under $XDG_CACHE_HOME/asdf-direnv/env. On most systems that resolves to ~/.config/asdf-direnv/env. It's always safe to remove files on this directory since they will be re-generated if missing.

If you ever need to regenerate a cached environment file, just touch .envrc.

Also, the asdf direnv envrc command will print the path to the cached environment file used for your project.

Now when you leave your project directory and come back to it, direnv will manage the environment variables for you really fast. For example:

direnv: loading .envrc
direnv: using asdf
direnv: Creating env file ~/.cache/asdf-direnv/env/909519368-2773408541-1591703797-361987458
direnv: loading ~/.cache/asdf-direnv/env/909519368-2773408541-1591703797-361987458
direnv: using asdf elixir 1.8.1-otp-21
direnv: using asdf nodejs 12.6.0
direnv: export +MIX_ARCHIVES +MIX_HOME +NPM_CONFIG_PREFIX ~PATH
Benchmark

benchmark

node --version

with asdf-direnv:

Mean [ms] Min [ms] Max [ms] Relative
4.3 ± 0.4 3.6 6.0 1.00

without asdf-direnv:

Mean [ms] Min [ms] Max [ms] Relative
189.7 ± 2.7 185.6 194.0 1.00
hyperfine 'node --version'

npm install -g yarn

with asdf-direnv:

Mean [ms] Min [ms] Max [ms] Relative
683.3 ± 17.3 667.9 725.1 1.00

without asdf-direnv:

Mean [ms] Min [ms] Max [ms] Relative
870.0 ± 12.9 848.4 894.6 1.00
hyperfine --cleanup 'npm uninstall -g yarn' 'npm install -g yarn'

Pro-Tips

  • Take a look at direnv help true.

  • Getting $ASDF_DIR/shims out of the PATH.

    Some users might want to bypass asdf shims altogether. To do so, include only $ASDF_DIR/bin in your PATH but exclude the shims directory.

    All shims are still available via asdf exec <shim>

    # ~/.bashrc or equivalent
    
    # Don't source `~/.asdf/asdf.sh`
    PATH="$PATH:~/.asdf/bin"

    Note: This will break any global defaults you have specified in ~/.tool-versions. There are various workarounds for this:

    • Do all work in project directories with their own .envrc and .tool-versions
    • Use asdf direnv shell for one-shot commands
    • Create a ~/.envrc with use asdf in it
    • Use your OS's package manager to install any tools you want globally accessible

    There are pros and cons to each of these approaches, it's up to you to pick the approach that works best for your workstyle.

  • If you want to silence the console output of direnv, you can do that by setting an empty environment variable: export DIRENV_LOG_FORMAT="".

  • Some times you might need to configure IDEs or other tools to find executables like package managers/code linters/compilers being used on a project of yours. For example, to execute npm outside your project directory you can do:

direnv exec /some/project npm
  • Remember that activation order is important.

    If a local .tool-versions file is present, the order of listed plugins will be preserved, so that toolA will be present before toolB in PATH.

# .tool-versions
toolA 1.0
toolB 2.0
  • You can use asdf even if current directory has no .tool-versions file.

    In this case the the activated versions will be the same than those returned by asdf current command.

  • You can override any tool version via environment variables.

    See the asdf documentation regarding versions from environment variables.

# .envrc
export ASDF_PLUGIN_VERSION=1.0
use asdf
  • Remember direnv can reload the environment whenever a file changes. By default this plugin will watch any .tool-versions file or legacy version file that explicitly selects a tool.

But you can easily watch more files when needed.

# .envrc
watch_file "package.json"
  • Using direnv status can be helpful to inspect current state. Also, you might want to take a look to direnv --help.

  • Using a non-empty ASDF_DIRENV_DEBUG will enable bash-tracing with set -x and skip env-cache.

    For example, if you are troubleshooting or trying to debug something weird on your environment, use export ASDF_DIRENV_DEBUG=true; direnv reload and provide any relevant output on an issue.

    Also, if you are contributing a new feature or bug-fix try running env ASDF_DIRENV_DEBUG=true bats -x test to run all tests with trace mode. If any test fails you will see more output.

Useful links

Read direnv documentation for more on .envrc.

If you are willing to contribute, be sure to read our CONTRIBUTING guide.

License

Licensed under the Apache License, Version 2.0.

More Repositories

1

asdf-python

Python plugin for the asdf version manager
Shell
664
star
2

asdf-golang

Go plugin for the asdf version manager
Shell
522
star
3

asdf-hashicorp

HashiCorp plugin for the asdf version manager
Shell
229
star
4

asdf-php

PHP plugin for the asdf version manager
Shell
214
star
5

asdf-deno

Deno plugin for the asdf version manager
Shell
121
star
6

asdf-kubectl

Kubectl plugin for the asdf version manager
Shell
120
star
7

asdf-flutter

flutter plugin for the asdf version manager
Shell
110
star
8

asdf-rust

Rust plugin for the asdf version manager
Shell
97
star
9

asdf-poetry

Poetry plugin for the asdf version manager
Shell
74
star
10

asdf-crystal

Crystal plugin for the asdf version manager
Shell
73
star
11

asdf-gleam

Gleam plugin for the asdf version manager
Shell
65
star
12

asdf-haskell

Haskell plugin for the asdf version manager
Shell
60
star
13

asdf-link

Use system tools with asdf version manager
Shell
51
star
14

asdf-zig

Zig plugin for the asdf version manager
Shell
43
star
15

asdf-kotlin

Kotlin plugin for the asdf version manager
Shell
40
star
16

asdf-plugin-manager

A plugin manager for the asdf version manager
Shell
38
star
17

asdf-alpine

Alpine Linux docker images of asdf tools
Shell
27
star
18

asdf-ocaml

OCaml plugin for the asdf version manager
Shell
27
star
19

asdf-elm

Elm plugin for the asdf version manager
Shell
25
star
20

asdf-ubuntu

Ubuntu docker images for asdf tools
Shell
23
star
21

asdf-nim

Nim plugin for the asdf version manager
Shell
22
star
22

asdf-scala

Scala plugin for the asdf version manager
Shell
22
star
23

asdf-graalvm

GraalVM plugin for the asdf version manager
Shell
19
star
24

infrastructure

Infrastructure configuration files
HCL
16
star
25

asdf-clojure

Clojure plugin for the asdf version manager
Shell
16
star
26

.github

asdf-community meta repository
15
star
27

asdf-haxe

Haxe plugin for the asdf version manager
Shell
14
star
28

asdf-opam

opam plugin for the asdf version manager
Shell
14
star
29

asdf-racket

Racket plugin for the asdf version manager
Shell
12
star
30

asdf-pdm

PDM plugin for the asdf version manager
Shell
8
star
31

asdf-sml

Standard ML plugin for the asdf version manager
Shell
7
star
32

asdf-ninja

Ninja plugin for the asdf version manager
Shell
7
star
33

asdf-aria2

aria2 plugin for the asdf version manager
Shell
7
star
34

asdf-lfe

LFE plugin for the asdf version manager
Shell
7
star
35

asdf-aocc

AMD Optimizing C/C++ Compiler plugin for the asdf version manager
Shell
6
star
36

asdf-dotty

dotty (Scala 3) plugin for the asdf version manager
Shell
6
star
37

asdf-chezscheme

Chez Scheme plugin for the asdf version manager
Shell
6
star
38

asdf-ccache

ccache plugin for the asdf version manager
Shell
6
star
39

asdf-mlton

MLton plugin for the asdf version manager
Shell
5
star
40

asdf-ktlint

ktlint plugin for the asdf version manager
Shell
5
star
41

asdf-peco

peco plugin for the asdf version manager
Shell
5
star
42

asdf-neko

Neko plugin for the asdf version manager
Shell
5
star
43

asdf-please

Please plugin for the asdf version manager
Shell
5
star
44

asdf-alp

alp plugin for the asdf version manager
Shell
5
star
45

asdf-meson

Meson plugin for the asdf version manager
Shell
5
star
46

asdf-mill

Mill plugin for the asdf version manager
Shell
5
star
47

asdf-idris2

Idris 2 plugin for the asdf version manager
Shell
5
star
48

asdf-lean

Lean plugin for the asdf version manager
Shell
4
star
49

asdf-esy

esy plugin for the asdf version manager
Shell
4
star
50

asdf-tuist

Tuist CLI plugin for the asdf version manager
Shell
4
star
51

asdf-odo

asdf version manager plugin for odo, the developer-focused CLI for fast and iterative application development on Podman, Kubernetes and OpenShift
Shell
4
star
52

asdf-idris

Idris plugin for the asdf version manager
Shell
3
star
53

asdf-quarkus

Quarkus plugin for the asdf version manager
Shell
3
star
54

asdf-rlwrap

rlwrap plugin for the asdf version manager
Shell
3
star
55

asdf-scala-cli

Scala CLI plugin for the asdf version manager
Shell
3
star
56

asdf-grpcurl

gRPCurl plugin for the asdf version manager
Shell
3
star
57

asdf-fstar

FStar plugin for the asdf version manager
Shell
3
star
58

asdf-cue

CUE plugin for the asdf version manager
Shell
2
star
59

asdf-uv

uv plugin for the asdf version manager
Shell
2
star
60

asdf-kiota

kiota plugin for the asdf version manager
Shell
2
star
61

asdf-cmctl

cmctl plugin for the asdf version manager
Shell
2
star
62

asdf-cmake

CMake plugin for the asdf version manager
Shell
2
star
63

asdf-getenvoy

GetEnvoy plugin for the asdf version manager
Shell
2
star
64

asdf-tridentctl

tridentctl plugin for the asdf version manager
Shell
1
star
65

asdf-moonrepo

Moon plugin for the asdf version manager
Shell
1
star
66

asdf-dprint

dprint plugin for the asdf version manager
Shell
1
star
67

asdf-dasel

Dasel plugin for asdf version manager
Shell
1
star
68

asdf-svu

SVU plugin for the asdf version manager
Shell
1
star
69

asdf-regal

regal plugin for the asdf version manager
Shell
1
star
70

asdf-mimirtool

mimirtool plugin for the asdf version manager
Shell
1
star
71

asdf-promtool

promtool plugin for the asdf version manager
Shell
1
star
72

asdf-duckdb

duckdb plugin for the asdf version manager
Shell
1
star