{"id":19,"date":"2022-05-04T14:52:17","date_gmt":"2022-05-04T19:52:17","guid":{"rendered":"https:\/\/jcshort.net\/?p=19"},"modified":"2023-03-22T16:36:50","modified_gmt":"2023-03-22T21:36:50","slug":"context-specific-tool-management-with-direnv-asdf","status":"publish","type":"post","link":"https:\/\/jcshort.net\/?p=19","title":{"rendered":"Context-specific tool management with direnv"},"content":{"rendered":"\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<p>I&#8217;ve tried juggling virtualenvs by hand.  Who has the time to manually activate and deactivate when jumping between projects?<\/p>\n\n\n\n<p>I&#8217;ve tried language-specific version managers.  Sometimes they work.  Sometimes you have to wait double-digit seconds for re-shimming.<\/p>\n\n\n\n<p>I&#8217;ve tried using tool-specific wrappers like tfenv.  The cognitive burden increases exponentially with each one added to the pile.<\/p>\n<\/div><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>But none of them solve the entire problem.  Maybe this project needs a specific version of Python.  Maybe that one is stuck on a weird version of Terraform.  Yet another is using a deprecated Helm version, but the package manager only has the latest patch in that series.<\/p>\n\n\n\n<p><a href=\"https:\/\/direnv.net\">Direnv<\/a> does a lot out of the box, but its strength is configuring projects to use an available version of a tool, it does not provide those versions itself.  Some languages have competent version manager tools that are worth using, but operational tools like terraform and kubectl generally lack version managers.<\/p>\n\n\n\n<p>That&#8217;s where <a href=\"https:\/\/asdf-vm.com\">asdf<\/a> comes in.  Not only is it a joy to type, when combined with direnv it&#8217;s actually <em>fast<\/em>.  Putting tool paths into a direnv include means no more waiting for slow re-shimming, running commands manually, or re-hashing your shell cache.<\/p>\n\n\n\n<p>It&#8217;s as simple as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">brew install direnv asdf\ndirenv hook\nasdf plugin add direnv\nasdf direnv setup --version system<\/code><\/pre>\n\n\n\n<p>You can then add <code>use asdf<\/code> to your <code>.envrc<\/code> file, and the plugin will modify PATH based on <code>.tool-versions<\/code>, e.g.:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">$ echo \"use asdf\" >> project\/.envrc\n$ direnv allow project\n$ cat &lt;&lt; EOF > project\/.tool-versions\nhelm 2.16.3\nkubectl 1.20.15\nterraform 0.14.11\nEOF<\/code><\/pre>\n\n\n\n<p>Now, not only is the python virtualenv automatically activated and deactivated, so are those tools:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">> $ cd project\ndirenv: loading ~\/project\/.envrc\ndirenv: using asdf\ndirenv: loading ~\/.cache\/asdf-direnv\/env\/2471675625-973451084-2702573808-1004245725\ndirenv: using asdf terraform 0.14.11\ndirenv: using asdf kubectl 1.20.15\ndirenv: using asdf helm 2.16.3\ndirenv: export ~PATH<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>But what about virtual environments?<\/strong><\/p>\n\n\n\n<p>asdf is great for managing tool versions, but some tools have <em>baggage<\/em>.  Like python virtual environments.  For that, we&#8217;ll need something a bit more specialized: pyenv.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ brew install pyenv\n$ echo _PYENV_DIR=\"$(pyenv prefix)\" >> ~\/.zshrc\n$ source ~\/.zshrc<\/code><\/pre>\n\n\n\n<p>direnv &#8220;layout&#8221; mode places files (such as virtualenvs) into the <code>~\/.direnv<\/code> folder within the project:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ echo \"layout pyenv 3.10.10\" >> project\/.envrc\n$ direnv allow project\n$ cd project\ndirenv: loading ~\/project\/.envrc\ndirenv: export +PYENV_VERSION +VIRTUAL_ENV ~PATH\n\n$ which python\n\/redacted\/project\/.direnv\/python-3.10.10\/bin\/python<\/code><\/pre>\n\n\n\n<p>Python packages can be managed normally from here via <code>pip<\/code>.  Similar plugins exist for node, ruby, etc, and can be found in the <a href=\"https:\/\/direnv.net\/man\/direnv-stdlib.1.html\">direnv stdlib man page<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve tried juggling virtualenvs by hand. Who has the time to manually activate and deactivate when jumping between projects? I&#8217;ve tried language-specific version managers. Sometimes they work. Sometimes you have to wait double-digit seconds for re-shimming. I&#8217;ve tried using tool-specific wrappers like tfenv. The cognitive burden increases exponentially with each one added to the pile. [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","footnotes":""},"categories":[1],"tags":[],"class_list":{"0":"post-19","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-tech","7":"entry"},"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"Jason Short","author_link":"https:\/\/jcshort.net\/?author=3"},"_links":{"self":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts\/19","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=19"}],"version-history":[{"count":0,"href":"https:\/\/jcshort.net\/index.php?rest_route=\/wp\/v2\/posts\/19\/revisions"}],"wp:attachment":[{"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=19"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=19"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jcshort.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=19"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}