189 lines
5.7 KiB
Nix
189 lines
5.7 KiB
Nix
{
|
|
pkgs,
|
|
config,
|
|
...
|
|
}:
|
|
{
|
|
config =
|
|
let
|
|
# control flow monstrosity
|
|
branchOnConfig =
|
|
cfg:
|
|
{
|
|
text,
|
|
file,
|
|
content,
|
|
contentFmt,
|
|
}:
|
|
if (cfg.text != "") then
|
|
text
|
|
else if (cfg.file != null) then
|
|
file
|
|
else if (cfg.content != { }) then
|
|
if (cfg.format != null) then
|
|
content
|
|
else if (cfg.formatter != null) then
|
|
contentFmt
|
|
else
|
|
throw "`format` or `formatter` must be set for `content` value ${cfg.content}!"
|
|
else
|
|
"";
|
|
in
|
|
{
|
|
# validate and complete the service configurations
|
|
_buildIdes.finalServices = builtins.mapAttrs (
|
|
name:
|
|
{
|
|
pkg,
|
|
args ? "",
|
|
exec ? "",
|
|
config,
|
|
path,
|
|
socket,
|
|
timer,
|
|
}:
|
|
let
|
|
# make our best effort to use the correct binary
|
|
bin = if (exec == "") then pkgs.lib.getExe pkg else pkgs.lib.getExe' pkg exec;
|
|
# set file extension
|
|
ext =
|
|
if (config.ext != "") || (config.format != null) then "." + (config.ext or config.format) else "";
|
|
# config hash for unique service names
|
|
cfgHash =
|
|
let
|
|
# method to hash a set
|
|
hashContent = builtins.hashString "sha256" (builtins.toJSON config.content);
|
|
in
|
|
branchOnConfig config {
|
|
text = builtins.hashString "sha256" config.text;
|
|
file = builtins.hashFile "sha256" config.file;
|
|
content = hashContent;
|
|
contentFmt = hashContent;
|
|
};
|
|
|
|
confFile =
|
|
let
|
|
writers = {
|
|
java = pkgs.formats.javaProperties { };
|
|
json = pkgs.formats.json { };
|
|
yaml = pkgs.formats.yaml { };
|
|
ini = pkgs.formats.ini { };
|
|
toml = pkgs.formats.toml { };
|
|
xml = pkgs.formats.xml { };
|
|
php = pkgs.formats.php { finalVariable = null; };
|
|
};
|
|
# final config name
|
|
confPath = "config-${name}-${cfgHash}${ext}";
|
|
in
|
|
# write out config
|
|
branchOnConfig config {
|
|
text = pkgs.writeText confPath config.text;
|
|
inherit (config) file;
|
|
content = writers.${config.format}.generate confPath config.content;
|
|
contentFmt = config.formatter confPath config.content;
|
|
};
|
|
# template the config path into the launch command
|
|
cfgArgs = builtins.replaceStrings [ "%CFG%" ] [ "${confFile}" ] args;
|
|
# flatten unit options into cli args
|
|
sdArgs =
|
|
let
|
|
inherit (pkgs.lib) foldlAttrs;
|
|
inherit (builtins) concatStringsSep;
|
|
convertToArgList =
|
|
prefix: name: values:
|
|
(map (inner: "${prefix} ${name}=${inner}") values);
|
|
writeArgListFor =
|
|
attrs: prefix:
|
|
if (attrs != { }) then
|
|
concatStringsSep " " (
|
|
foldlAttrs (
|
|
acc: n: v:
|
|
acc + (convertToArgList prefix n v) + " "
|
|
) "" attrs
|
|
)
|
|
else
|
|
"";
|
|
in
|
|
concatStringsSep " " [
|
|
(writeArgListFor socket "--socket-property")
|
|
(writeArgListFor path "--path-property")
|
|
(writeArgListFor timer "--timer-property")
|
|
];
|
|
in
|
|
# transform into attrs that mkWorks expects to receive
|
|
{
|
|
inherit
|
|
bin
|
|
sdArgs
|
|
cfgArgs
|
|
;
|
|
unitName = "shell-${name}-${cfgHash}";
|
|
}
|
|
) config.serviceDefs;
|
|
|
|
# generate service scripts and create the shell
|
|
_buildIdes.shell =
|
|
let
|
|
# create commands to run and clean up services
|
|
mkWorks =
|
|
name:
|
|
{
|
|
unitName,
|
|
bin,
|
|
cfgArgs,
|
|
sdArgs,
|
|
}:
|
|
{
|
|
runner = pkgs.writeShellScriptBin "run" ''
|
|
echo "[ides]: starting ${name}.."
|
|
systemd-run --user -G -u ${unitName} ${sdArgs} ${bin} ${cfgArgs}
|
|
'';
|
|
cleaner = pkgs.writeShellScriptBin "clean" ''
|
|
echo "[ides]: stopping ${name}.."
|
|
systemctl --user stop ${unitName}
|
|
'';
|
|
};
|
|
|
|
works = pkgs.lib.mapAttrs (
|
|
name: serviceConf: mkWorks name serviceConf
|
|
) config._buildIdes.finalServices;
|
|
|
|
# create the ides cli
|
|
cli = import ./cli.nix {
|
|
inherit (pkgs) writeShellScriptBin;
|
|
inherit (pkgs.lib) foldlAttrs;
|
|
inherit works;
|
|
};
|
|
|
|
# create the ides shell
|
|
final =
|
|
let
|
|
inherit (config._buildIdes) shellArgs;
|
|
in
|
|
shellArgs
|
|
// {
|
|
nativeBuildInputs = (shellArgs.nativeBuildInputs or [ ]) ++ [
|
|
cli
|
|
];
|
|
shellHook =
|
|
let
|
|
autoRun =
|
|
if config.auto then
|
|
''
|
|
ides run
|
|
''
|
|
else
|
|
"";
|
|
in
|
|
(shellArgs.shellHook or "")
|
|
+ ''
|
|
printf '[ides]: use "ides [action] [target]" to control services. type "ides help" to find out more.\n'
|
|
''
|
|
+ autoRun;
|
|
};
|
|
in
|
|
config._buildIdes.shellFn final;
|
|
};
|
|
|
|
}
|