asdf icon indicating copy to clipboard operation
asdf copied to clipboard

Non-language plugins

Open excid3 opened this issue 7 years ago • 13 comments

Rbenv allows you to install plugins that hook into more functionality of the version manager. For example, rbenv-vars allows you to set project specific environment variables and are automatically loaded when Ruby is executed.

I've replicated this for asdf called asdf-vars, but right now I have to inject into the asdf-exec script to add this functionality. The downside is that this is going to cause a conflict when updating asdf in the future.

There's a list of other interesting plugins here: https://github.com/rbenv/rbenv/wiki/Plugins

These are the hooks that they support for plugins: https://github.com/rbenv/rbenv/wiki/Authoring-plugins#rbenv-hooks

Would adding hooks to support non-language plugins to asdf be something that would get accepted as a PR or is already on the roadmap?

excid3 avatar Oct 02 '18 01:10 excid3

It depends on those hooks are implemented. I do think there is a need for something like this, but I want to make sure the solution we come up with is generic enough to satisfy all the possible use cases. We've already got a need for something like asdf-vars in several other plugins. For example, the Erlang plugin reads certain environment variables during installation, and Erlang itself also reads other environment variables at runtime. There is definitely a need for a more standardized way of making sure environment variables are set before compilation or execution of a program.

So to answer your question, yes, we definitely want something like this. But we want to make sure it's the right solution so we don't have to revisit this in the future.

For asdf-vars, I think we could potentially bake that functionality right into asdf. Imagine an optional .asdf-ruby-compile-env and .asdf-ruby-runtime-env files that get sourced before compilation and before runtime. asdf would just look for files matching the pattern .asdf-<plugin name>-*-env and it would work across the board for all plugins with no changes necessary to any of the plugins.

For more generalized "before exec" hooks we'd want to make it easy for the user to plug in anything they wanted without having to jump through too many hoops. We'd also want to limit the scope of the "before exec" hook. The hook shouldn't be responsible for directory traversal, version manipulation, or need to duplicate any of the existing functionality of asdf.

Stratus3D avatar Oct 02 '18 14:10 Stratus3D

I want to clarify too, my use case for asdf-vars is actually more for setting environment variables for apps separately.

For example, I can set DATABASE_URL=whatever in .asdf-vars in two different folders which allows my apps to run on the same machine without conflicts.

This could be useful for other things, but I don't know of enough of the use cases where you'd want something like -compile-env and -runtime-env etc. A generic version might actually cover most things, but I'd be curious to hear about other use cases.

excid3 avatar Oct 02 '18 18:10 excid3

I fear there will be a tension here between environment variables that are part of your personal setup (e.g. the local DB port/URL as you suggest, or the local path to a sibling repository) and environment variables that you want set consistently for everyone working on the project (e.g. compilation flags for Erlang). I could even imagine someone wanting a different environment variable file for production.

I very much appreciate this idea for both use cases presented so far, but already there seems to be a conflict at the level of "do I want to track this file in version control?" What happens when you want both?

Jwashton avatar Oct 02 '18 19:10 Jwashton

Agreed. And one thing that asdf-vars / rbenv-vars does is recursively look up the folder stack for vars files. That way you could keep shared variables in version control and production can have it's own, untracked vars in a parent folder. The merging allows you some flexibility there.

excid3 avatar Oct 02 '18 20:10 excid3

@excid3 yes, we could have to traverse your directory structure looking for a .asdf-ruby-vars file until it finds one. Placing one in your project would set env vars just for that project, placing one in parent directory would set env vars for that dir and all sub dirs.

@Jwashton yes that is a concern. Check personal settings into VC could be a problem. Of course we could tell people not to check the env files in, or to only check in sample env files that would be renamed by the user. I'm on the fence about this feature. I can see benefits to having it, but it would have the potential to cause a lot of problems.

This is my mindset when figuring out how proposed features should be implemented:

  • If it can just as easily be done outside of asdf it should
  • If it can't be done outside of asdf, but could if a hook or API were added to asdf, that hook or API should be implemented and the feature implemented outside of asdf. Unless the feature will be needed by everyone, in which case it can be added to asdf.
  • If it can only be implemented in asdf, or it is a feature needed by all asdf users, then it should be added to asdf itself.

I'm not really sure where this feature falls.

Stratus3D avatar Oct 08 '18 15:10 Stratus3D

I believe there's a great tool for the use case of per-project environment variables already: https://direnv.net/

In the unix spirit it does one thing and does it well. It also has a feature to "authorize" a .envrc file to ensure you are not exposed to risky env vars from projects you clone and cd into.

neerfri avatar Oct 09 '18 11:10 neerfri

I think the one downside of direnv is that it installs itself by prepending it self to your prompt so it gets triggered every time.

Correct me if I'm wrong, but this won't work if you're over SSH using a non-login, non-interactive shell, which is what I'm considering using asdf with.

_direnv_hook() {
  local previous_exit_status=$?;
  eval "$(direnv export bash)";
  return $previous_exit_status;
};
if ! [[ "$PROMPT_COMMAND" =~ _direnv_hook ]]; then
  PROMPT_COMMAND="_direnv_hook;$PROMPT_COMMAND";
fi

excid3 avatar Oct 11 '18 17:10 excid3

I'm not familiar with direnv, but I do know it's far more intrusive than asdf. All asdf really does is stick a few things on your PATH.

Stratus3D avatar Oct 11 '18 20:10 Stratus3D

I just came across a situation where I'd like to create some directories after redis is installed, which would be a perfect use for a post-install hook. It would be great for setting up config files too.

mwean avatar Oct 17 '18 00:10 mwean

I've been putting together a PR that adds support for intrusive plugins, in two main ways:

  • Allow plugins to intercept the command and arguments that asdf was invoked with, and do post-processing/redirection on them before any command is dispatched
  • Allow plugins to provide porcelain commands that are dispatched when asdf doesn't recognize a command name.

So given my proposal about aliases, a possible approach would be:

  1. Implement porcelain for alias-add, alias-remove, alias-list
  2. Implement a post-processing hook that inspects the command being invoked, and if the command takes a version, try to resolve that version as an alias - if an alias is found, then modify the argument list so that the version is swapped with the resolved ("real") version mapped to the alias.

I looked into adding hooks to various points in the utils/command scripts, but the reality is that there is no sane way to do so without making large portions of the internals effectively a public API. The advantage of the approach above is that plugins can modify any public env vars, perform arbitrary work at initialization, and can transparently modify the command/arguments asdf will dispatch on - and that's a powerful tool set, but ultimately the burden is on the plugin author, not the asdf maintainers. By allowing dispatch to plugin porcelain in the case of unresolved commands, plugins can feel like a natural part of the CLI, and again without imposing any maintenance burden on the asdf maintainers.

I haven't had time to experiment further, but figured I'd leave my notes here for feedback.

bitwalker avatar May 22 '19 00:05 bitwalker

Hi, I was wondering if there was an update on this issue. I'm interested in using asdf to add env vars like asdf works for other tools. Getting everyone on my team to follow the install steps at the top of this issue would be suboptimal. I also found this plugin that might be a little easier to setup: https://github.com/asdf-community/asdf-direnv

jakepearson avatar Sep 19 '23 15:09 jakepearson

For anyone curious, I forked asdf and added asdf vars that loads .asdf-vars files and evaluates them during exec.

https://github.com/asdf-vm/asdf/compare/master...excid3:asdf:master

excid3 avatar Sep 19 '23 17:09 excid3

For anyone curious, I forked asdf and added asdf vars that loads .asdf-vars files and evaluates them during exec.

master...excid3:asdf:master

Cool, will this get merged to main asdf?

jakepearson avatar Sep 19 '23 18:09 jakepearson