From 5fa89f8dd61767b97fdd83b1327f7746fd7521fd Mon Sep 17 00:00:00 2001 From: Chris Gaudreau Date: Fri, 3 Jan 2025 15:34:29 -0400 Subject: [PATCH] Add simple elixir plugin (#2462) ## Summary Adds a very basic elixir plugin to simplify installation to a simple `devbox add elixir`. Also now properly stores Mix/Hex artifacts in `.devbox/virtenv`. ## How was it tested? - Tested it against the existing elixir example in the repo. Seems to work fine. - Tested on my own projects as well, separately on Mac + Ubuntu. --- .../docs/devbox_examples/languages/elixir.md | 56 ++++++++++++------- docs/app/docs/guides/plugins.md | 3 +- .../elixir/elixir_hello/devbox.json | 15 +---- .../elixir/elixir_hello/devbox.lock | 23 ++++---- plugins/builtins.go | 1 + plugins/elixir.json | 14 +++++ 6 files changed, 69 insertions(+), 43 deletions(-) create mode 100644 plugins/elixir.json diff --git a/docs/app/docs/devbox_examples/languages/elixir.md b/docs/app/docs/devbox_examples/languages/elixir.md index ef746fd159e..c0ba80ef44a 100644 --- a/docs/app/docs/devbox_examples/languages/elixir.md +++ b/docs/app/docs/devbox_examples/languages/elixir.md @@ -2,7 +2,7 @@ title: Elixir --- -Elixir can be configured to install Hex and Rebar dependencies in a local directory. This will keep Elixir from trying to install in your immutable Nix Store: +Elixir can be installed by simply running `devbox add elixir`. This will automatically include the Elixir Plugin to isolate Mix/Hex artifacts and enable shell history in `iex`. [**Example Repo**](https://github.com/jetify-com/devbox/tree/main/examples/development/elixir/elixir_hello) @@ -10,33 +10,51 @@ Elixir can be configured to install Hex and Rebar dependencies in a local direct ## Adding Elixir to your project -`devbox add elixir bash`, or add the following to your `devbox.json` +`devbox add elixir`, or add the following to your `devbox.json` ```json "packages": [ - "elixir@latest", - "bash@latest" + "elixir@latest" ], ``` -This will install the latest version of Elixir available. You can find other installable versions of Elixir by running `devbox search elixir`. You can also search for Elixir on [Nixhub](https://www.nixhub.io/packages/elixir) +This will install the latest version of Elixir. You can find other installable versions of Elixir by running `devbox search elixir`. You can also search for Elixir on [Nixhub](https://www.nixhub.io/packages/elixir) -## Installing Hex and Rebar locally +## Elixir Plugin Support -Since you are unable to install Elixir Deps directly into the Nix store, you will need to configure mix to install your dependencies globally. You can do this by adding the following lines to your `devbox.json` init_hook: +Devbox will automatically use the following configuration when you install Elixir with `devbox add`. + +### Environment Variables + +`$MIX_HOME` and `$HEX_HOME` configure Mix/Hex to install artifacts locally, while `$ERL_AFLAGS` enables shell history in `iex`: + +```bash +MIX_HOME={PROJECT_DIR}/.devbox/virtenv/elixir/mix +HEX_HOME={PROJECT_DIR}/.devbox/virtenv/elixir/hex +ERL_AFLAGS="-kernel shell_history enabled" +``` + +### Disabling the Elixir Plugin + +You can disable the Elixir plugin by running `devbox add elixir --disable-plugin`, or by setting the `disable_plugin` field in your `devbox.json`: ```json - "shell": { - "init_hook": [ - "mkdir -p .nix-mix", - "mkdir -p .nix-hex", - "export MIX_HOME=$PWD/.nix-mix", - "export HEX_HOME=$PWD/.nix-hex", - "export ERL_AFLAGS='-kernel shell_history enabled'", - "mix local.hex --force", - "mix local.rebar --force" - ] - } +{ + "packages": { + "elixir": { + "version": "latest", + "disable_plugin": true + } + }, +} ``` -This will create local folders and force mix to install your Hex and Rebar packages to those folders. Now when you are in `devbox shell`, you can install using `mix deps`. +Note that disabling the plugin will cause Mix and Hex to cache artifacts globally in the user's home directory (at `~/.mix/` and `~/.hex/`). This might actually be preferable if you're developing several Elixir projects and want to benefit from caching, but does defeat the isolation guarantees of Devbox. + +If the plugin is disabled, it's recommended to manually set `$ERL_AFLAGS` to preserve `iex` shell history: + +```json + "env": { + "ERL_AFLAGS": "-kernel shell_history enabled" + } +``` \ No newline at end of file diff --git a/docs/app/docs/guides/plugins.md b/docs/app/docs/guides/plugins.md index ca73e44beb3..8ada46a3c16 100644 --- a/docs/app/docs/guides/plugins.md +++ b/docs/app/docs/guides/plugins.md @@ -8,7 +8,7 @@ This doc describes how to use Devbox Plugins with your project. **Plugins** prov ### Built-in Plugins -If you add one of the packages listed above to your project using `devbox add `, Devbox will automatically activate the plugin for that package. +If you add one of the packages listed below to your project using `devbox add `, Devbox will automatically activate the plugin for that package. You can also explicitly add a built-in plugin in your project by adding it to the [`include` section](../configuration.md#include) of your `devbox.json` file. For example, to explicitly add the plugin for Nginx, you can add the following to your `devbox.json` file: @@ -34,6 +34,7 @@ Built-in plugins are available for the following packages. You can activate the * [PHP](../devbox_examples/languages/php.md) (php, php80, php81, php82...) * [Python](../devbox_examples/languages/python.md) (python, python-full, python-minimal...) * [Ruby](../devbox_examples/languages/ruby.md)(ruby, ruby_3_1, ruby_3_0...) +* [Elixir](../devbox_examples/languages/elixir.md)(elixir, elixir_1_16, elixir_1_15...) ### Local Plugins diff --git a/examples/development/elixir/elixir_hello/devbox.json b/examples/development/elixir/elixir_hello/devbox.json index da1672f1066..9bc72c554dc 100644 --- a/examples/development/elixir/elixir_hello/devbox.json +++ b/examples/development/elixir/elixir_hello/devbox.json @@ -1,18 +1,9 @@ { - "packages": { - "elixir": "latest" - }, - "env": { - "MIX_HOME": "$PWD/.nix-mix", - "HEX_HOME": "$PWD/.nix-hex", - "ERL_AFLAGS": "-kernel shell_history enabled" - }, + "packages": [ + "elixir@latest" + ], "shell": { "init_hook": [ - "mkdir -p .nix-mix", - "mkdir -p .nix-hex", - "mix local.hex --force", - "mix local.rebar --force", "mix deps.get" ], "scripts": { diff --git a/examples/development/elixir/elixir_hello/devbox.lock b/examples/development/elixir/elixir_hello/devbox.lock index e53ac95fb62..0a47a5dd787 100644 --- a/examples/development/elixir/elixir_hello/devbox.lock +++ b/examples/development/elixir/elixir_hello/devbox.lock @@ -2,50 +2,51 @@ "lockfile_version": "1", "packages": { "elixir@latest": { - "last_modified": "2024-02-10T18:15:24Z", - "resolved": "github:NixOS/nixpkgs/10b813040df67c4039086db0f6eaf65c536886c6#elixir", + "last_modified": "2024-11-28T07:51:56Z", + "plugin_version": "0.0.1", + "resolved": "github:NixOS/nixpkgs/226216574ada4c3ecefcbbec41f39ce4655f78ef#elixir", "source": "devbox-search", - "version": "1.15.7", + "version": "1.17.3", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/kf294q6pwmqv8hb5ivis509y1wjjgm09-elixir-1.15.7", + "path": "/nix/store/91w79z55qsjkhnbs3a21l3h27va98mf6-elixir-1.17.3", "default": true } ], - "store_path": "/nix/store/kf294q6pwmqv8hb5ivis509y1wjjgm09-elixir-1.15.7" + "store_path": "/nix/store/91w79z55qsjkhnbs3a21l3h27va98mf6-elixir-1.17.3" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/f5x2w7df45vahjcpjf76dv101il8xq98-elixir-1.15.7", + "path": "/nix/store/pz4hk0sp4zj76waaprlfdmvc4xdblz55-elixir-1.17.3", "default": true } ], - "store_path": "/nix/store/f5x2w7df45vahjcpjf76dv101il8xq98-elixir-1.15.7" + "store_path": "/nix/store/pz4hk0sp4zj76waaprlfdmvc4xdblz55-elixir-1.17.3" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/6vv8qlvhpi62nk5d06lhi5isvlg7bcj9-elixir-1.15.7", + "path": "/nix/store/gnjg57wv71svvqw7s3rxyjc6lkps2r95-elixir-1.17.3", "default": true } ], - "store_path": "/nix/store/6vv8qlvhpi62nk5d06lhi5isvlg7bcj9-elixir-1.15.7" + "store_path": "/nix/store/gnjg57wv71svvqw7s3rxyjc6lkps2r95-elixir-1.17.3" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/dlq14nswvq479pmnrwlyn2hyk6cwp65a-elixir-1.15.7", + "path": "/nix/store/rx7qr8bar4qldx6yg3njvm8hn84d3yyk-elixir-1.17.3", "default": true } ], - "store_path": "/nix/store/dlq14nswvq479pmnrwlyn2hyk6cwp65a-elixir-1.15.7" + "store_path": "/nix/store/rx7qr8bar4qldx6yg3njvm8hn84d3yyk-elixir-1.17.3" } } } diff --git a/plugins/builtins.go b/plugins/builtins.go index ac4c8180eb6..346b19c236d 100644 --- a/plugins/builtins.go +++ b/plugins/builtins.go @@ -27,6 +27,7 @@ type BuiltIn struct{} var builtInMap = map[*regexp.Regexp]string{ regexp.MustCompile(`^(apache|apacheHttpd)$`): "apacheHttpd", regexp.MustCompile(`^(gradle|gradle_[0-9])$`): "gradle", + regexp.MustCompile(`^elixir_?([0-9_]*[0-9]+)?$`): "elixir", regexp.MustCompile(`^(ghc|haskell\.compiler\.(.*))$`): "haskell", regexp.MustCompile(`(^mariadb(-embedded)?_?[0-9]*$|^mysql$)`): "mariadb", regexp.MustCompile(`^mysql(80|57|50)$`): "mysql", diff --git a/plugins/elixir.json b/plugins/elixir.json new file mode 100644 index 00000000000..49cc2656d63 --- /dev/null +++ b/plugins/elixir.json @@ -0,0 +1,14 @@ +{ + "name": "elixir", + "version": "0.0.1", + "packages": { + "darwin.apple_sdk.frameworks.CoreServices": { + "platforms": ["aarch64-darwin", "x86_64-darwin"] + } + }, + "env": { + "MIX_HOME": "{{ .Virtenv }}/mix", + "HEX_HOME": "{{ .Virtenv }}/hex", + "ERL_AFLAGS": "-kernel shell_history enabled" + } +}