devshell/lib/modules/env.nix

136 lines
3.8 KiB
Nix
Raw Normal View History

2025-07-31 12:37:19 +02:00
{
lib,
pkgs,
config,
...
}: let
inherit (lib) filter assertMsg head length escapeShellArg types mkOption concatStringsSep;
envToBash = {
name,
value,
eval,
prefix,
...
} @ args: let
vals = filter (key: args.${key} != null && args.${key} != false) [
2025-07-31 12:37:19 +02:00
"eval"
"prefix"
"unset"
"value"
];
valType = head vals;
in
assert assertMsg (
(length vals) > 0
) "[devshell/env]: ${name} expected one of (value|eval|prefix|unset) to be set.";
assert assertMsg ((length vals) < 2)
"[devshell/env]: ${name} expected only one of (value|eval|prefix|unset) to be set. Not ${toString vals}";
assert assertMsg (!(name == "PATH" && valType == "value")) "[devshell/env]: ${name} should not override the value. Use 'prefix' instead.";
if valType == "value"
then "export ${name}=${escapeShellArg (toString value)}"
else if valType == "eval"
then "export ${name}=${eval}"
else if valType == "prefix"
then ''export ${name}=$(${pkgs.coreutils}/bin/realpath --canonicalize-missing "${prefix}")''${${name}+:''${${name}}}''
else if valType == "unset"
then ''unset ${name}''
else throw "[devshell] BUG in the env module. This should never be reached.";
envType = types.submodule ({name, ...}: {
options = {
name = mkOption {
type = types.str;
default = name;
description = ''
Name of the environment variable, usually already set to `<name>`.
'';
};
desc = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Description of the env var, can be shown in the menu.
'';
};
visible = mkOption {
type = types.bool;
default = true;
description = ''
Whether to include this env var and it's description in the menu.
'';
2025-07-31 12:37:19 +02:00
};
value = mkOption {
type = with types;
nullOr (oneOf [
str
int
bool
package
]);
default = null;
example = "hello";
description = ''
Any value to convert to a string and set the env variable to.
There is no evaluation of the value, for that see [eval](#envnameeval).
'';
2025-07-31 12:37:19 +02:00
};
eval = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Like value but evaluated by Bash. This allows to inject other
2025-07-31 12:37:19 +02:00
variable names or even commands using the `$()` notation.
'';
example = "$OTHER_VAR";
};
prefix = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Prepend to PATH-like environment variables.
For example `name = "PATH"; prefix = "bin";` will expand the path of
`./bin` and prepend it to the `PATH`, separated by `:`.
2025-07-31 12:37:19 +02:00
'';
example = "bin";
};
unset = mkOption {
type = types.bool;
default = false;
description = ''
Unset the env variable.
'';
2025-07-31 12:37:19 +02:00
};
};
});
in {
options.env = mkOption {
type = types.attrsOf envType;
default = {};
description = ''
Manage environment variables.
'';
2025-07-31 12:37:19 +02:00
};
config = {
env = {
"XDG_DATA_DIRS".eval = "$DEVSHELL_DIR/share:\${XDG_DATA_DIRS-}";
};
enterShellCommands."env".text = concatStringsSep "\n" (map envToBash (builtins.attrValues config.env));
# TODO: collect all env vars, then add them to the menu if they have a description and "visibile == true"
2025-09-15 11:28:58 +02:00
meta = {
sections."Environment Variables".color = "red";
entries."XDG_DATA_DIRS" = {
description = "Hello world";
section = "Environment Variables";
subEntries."Usage" = "hello world";
};
};
2025-07-31 12:37:19 +02:00
};
}