devshell/lib/modules/main.nix

136 lines
3.1 KiB
Nix
Raw Permalink Normal View History

2025-07-31 12:37:19 +02:00
{
pkgs,
lib ? pkgs.lib,
config,
...
}: let
inherit (lib) mapAttrs mkOption types textClosureMap id attrNames;
mkNakedShell = pkgs.callPackage ./../utils/mkNakedShell.nix {};
addAttributeName = prefix:
mapAttrs (
k: v:
v
// {
text = ''
#### ${prefix}.${k}
${v.text}
'';
}
);
envBash =
pkgs.writeText "devshell-env.bash"
# sh
''
export DEVSHELL_DIR=@DEVSHELL_DIR@
# nicely handle it at the front or between/end
PATH=''${PATH#/path-not-set:}
PATH=''${PATH#:/path-not-set}
export PATH=$DEVSHELL_DIR/bin:$PATH
${textClosureMap
id
(addAttributeName "startup" config.enterShellCommands)
(attrNames config.enterShellCommands)}
# interactive session
if [[ $- == *i* ]]; then
true
${textClosureMap
id
(addAttributeName "interactive" config.interactiveShellCommands)
(attrNames config.interactiveShellCommands)}
fi # interactive session
unset DEVSHELL_DIR
'';
entryType = types.submodule {
options = {
text = mkOption {
type = types.str;
description = ''
Script to run.
'';
};
deps = mkOption {
type = types.listOf types.str;
default = [];
description = ''
A list of other steps that this one depends on.
'';
};
};
};
in {
options = {
shell = {
finalPackage = mkOption {
type = types.package;
internal = true;
};
finalProfile = mkOption {
type = types.package;
internal = true;
};
};
name = mkOption {
type = types.str;
default = "devshell";
description = ''
Name of the shell.
'';
2025-07-31 12:37:19 +02:00
};
packages = mkOption {
type = types.listOf types.package;
default = [];
description = ''
Packages to install into the devshell.
'';
2025-07-31 12:37:19 +02:00
};
enterShellCommands = mkOption {
type = types.attrsOf entryType;
default = {};
description = ''
Commands to run when entering the shell.
'';
example = {
"hello".text = "echo Hello world";
};
2025-07-31 12:37:19 +02:00
};
interactiveShellCommands = mkOption {
type = types.attrsOf entryType;
default = {};
description = ''
Commands to run when entering an interactive shell.
'';
example = {
"hello".text = "echo Hello world";
};
2025-07-31 12:37:19 +02:00
};
};
config.shell = {
finalProfile = pkgs.buildEnv {
name = "${config.name}-profile";
paths = config.packages;
postBuild = ''
substitute ${envBash} $out/env.bash --subst-var-by DEVSHELL_DIR $out
# NOTE: maybe also add an entrypoint shell script at $out/bin/devshell-${config.name}?
'';
meta.mainProgram = "devshell-${config.name}";
};
finalPackage = mkNakedShell {
2025-09-15 11:28:58 +02:00
inherit (config) name;
2025-07-31 12:37:19 +02:00
profile = config.shell.finalProfile;
2025-09-15 11:28:58 +02:00
passthru = {
metadata = config.meta.finalMetadata;
metadataJson = config.meta.finalJson;
};
2025-07-31 12:37:19 +02:00
};
};
}