[ENHANCEMENT] Multiple devenv(-up) profiles/variants
Concrete use case:
I have a devenv.nix in the root of our repo to run everything together. Now depending on different development focus, we would love to either pass variables for devenv to evaluate (think --no-frontend) or to have multiple devenv profiles where we could e.g. say devenv up --backend-only. Similar to a flake's `nix develop '.#profile'.
I know that this should be possible with flakes, but since the rest of the team is not "nix-native" and we really enjoy the abstraction devenv brings, this would be a killer feature.
What would be necessary to build this up?
We'd need to use something like https://github.com/shakacode/steward to run our processes and then expose interface to start only specific ones
Alternatively, add devenv.<name>.{packages,services,tasks,...} and allow composing setups through the module system and imports.
For example:
devenv.default = {
imports = [
config.outputs.frontendModule
config.outputs.backendModule
];
};
devenv.frontend = {
imports = [ config.outputs.frontendModule ];
};
devenv.backend = {
imports = [ config.outputs.backendModule ];
};
outputs.frontendModule = {
services.nginx.enable = true;
# ...
};
outputs.backendModule = {
services.postgres.enable = true;
# ...
};
While I think it would be nice to have profiles, as they would be an official solution to this problem and enter the documentation, there's a workaround via environment variables.
In devenv.nix use
scripts = {
only.exec = ''
echo "checking if ENV is in: $*"
for arg in "$@"; do
if [ "$arg" == "$ENV" ]; then
echo "ENV ($ENV) matched"
exit 1
fi
done
echo "ENV not matched, exiting"
exit 0
'';
};
processes = {
start-frontend.exec = ''only frontend && exit ; echo "running frontend" '';
start-backend.exec = ''only backend && exit ; echo "running backend" '';
start-common.exec = ''only backend frontend && exit ; echo "running common"'';
};
then start it with
ENV=backend devenv up
the script will try to match ENV with each parameter string and, if none matches, the && exit will run.
I hope this helps someone; maybe this could be added somewhere in the docs.
EDIT: I guess this could be made nicer by wrapping it in some nix expression that makes it nicer to look at, like
processes.start-frontend.exec = only [ "frontend" ] ''echo starting frontend'';
and I think it could be even refactored to move it up higher
processes = only {
"frontend" = {
start-frontend = "echo starting frontend";
};
};
or something like this.
Well, I ended up making a specific tool for this: https://codeberg.org/akiross/run-only
It's used like this:
{ pkgs, inputs, ... }:
{
processes = inputs.run-only.on-env pkgs {
# Plain definition, always executed
always.exec = "...";
# Common for backend and frontend
common = { exec = "..."; profiles = [ "backend" "frontend" ]; };
# Only backend
backend = { exec = "..."; profiles = [ "backend" ]; };
# Both stats and backend profiles
stats = { exec = "..."; profiles = [ "stats" "backend" ]; };
# Only backend
frontend = { exec = "..."; profiles = [ "frontend" ]; };
};
}
and then
ENV=backend devenv up
I hope it helps!
I've written up a guide that allows this (finally!): https://github.com/cachix/devenv/pull/1841
Does that fit into what you need?
Exactly what I want - this is perfect! Thank you.
A follow up question though - how does this work with other devenv.nix files? I think this should also be possible since everything gets evaluated together. That would mean all options get imported as well - what if i have options with the same name imported from different files? Does nix throw an error?
Scenario: Dev tools in path monorepo/frontend
- I want the dev tools in the frontend environment
- but when frontend is imported as part of the main app, I dont want them
- have an option "devtools" in the specific devenv.nix in frontend (maybe also in backend, etc) I guess one could:
- set this option as default with higher prio to false in the main devenv.nix
- and then create the cascading options, like --release or --frontend-only which affect different parts
Overall - excited to start playing around with 1.6 🎉
A follow up question though - how does this work with other devenv.nix files?
It works, you can now set profile option in any devenv file you're importing!
That would mean all options get imported as well - what if i have options with the same name imported from different files? Does nix throw an error?
Yes, that's a conflict option error.
Scenario: Dev tools in path monorepo/frontend
You can add options like myproject.frontend.enable and myproject.backend.enable, etc... If you want more granuality.