{ lib, config, pkgs, ... }:
let
t = v: builtins.trace v v;
filterAttrs' = l: lib.filterAttrs (v: _: builtins.elem v l);
cfg = config.retronix.emulationstation;
attrToXml = attrs: lib.concatLines (lib.mapAttrsToList (k: v: "<${k}>${builtins.toString v}${k}>") attrs);
gameTemplate = game: let
attr = [
"path"
"name"
"sortname"
"desc"
"image"
"video"
"marquee"
"thumbnail"
"rating"
"releasedate"
"developer"
"publisher"
"genre"
"players"
"favorite"
"hidden"
"kidgame"
"playcount"
"lastplayed"
];
args = game.meta // { path = "@out@/${game.name}.sh"; };
in ''
${attrToXml (filterAttrs' attr args)}
'';
systemTemplate = args: let
attr = [
"name"
"fullname"
"path"
"extension"
"command"
"platform"
"theme"
];
in ''
${attrToXml (filterAttrs' attr args)}
'';
mkSystemPath = name: games: let
gamelist = ''
${lib.concatLines (builtins.map gameTemplate games)}
'';
symlinkCommands = builtins.map (
v: "ln -s ${v}/${v.launchPath} $out/${v.name}.sh"
) games;
in pkgs.runCommand "${name}-roms" {
inherit gamelist symlinkCommands;
passAsFile = [
"gamelist"
];
} ''
mkdir -p $out
cp $gamelistPath $out/gamelist.xml
substituteAllInPlace $out/gamelist.xml
${lib.concatLines symlinkCommands}
'';
sectionOptions = lib.types.submodule ({config, name, ...}: {
freeformType = with lib.types; attrsOf str;
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
};
fullname = lib.mkOption {
type = lib.types.str;
default = name;
};
path = lib.mkOption {
type = lib.types.path;
};
command = lib.mkOption {
type = lib.types.str;
default = "%ROM%";
};
extension = lib.mkOption {
type = lib.types.str;
};
games = lib.mkOption {
type = lib.types.listOf lib.types.package;
description = "Takes attributes of `games` tag in gamelist.xml";
};
};
config = {
path = mkSystemPath config.name config.games;
};
});
in {
options = {
retronix = {
emulationstation = {
systemCfgFile = lib.mkOption {
type = lib.types.path;
};
inputCfgFile = lib.mkOption {
type = lib.types.path;
};
settingsCfgFile = lib.mkOption {
type = lib.types.path;
};
themesDir = lib.mkOption {
type = lib.types.path;
};
themes = lib.mkOption {
type = lib.types.attrsOf lib.types.path;
default = {};
};
inputCfg = lib.mkOption {
type = lib.types.str;
default = "";
};
homeDir = lib.mkOption {
internal = true;
type = lib.types.path;
};
extraConfigFiles = lib.mkOption {
type = with lib.types; listOf path;
default = [];
description = ''
Must be store paths.
Directory structure will be merged.
'';
};
cli = lib.mkOption {
type = lib.types.package;
};
};
systems = lib.mkOption {
type = lib.types.attrsOf (sectionOptions);
default = {};
};
};
};
config = {
retronix.emulationstation = {
systemCfgFile = pkgs.writeTextDir "es_systems.cfg" ''
${lib.concatLines (lib.mapAttrsToList (_: systemTemplate) config.retronix.systems)}
'';
inputCfgFile = lib.mkDefault (pkgs.writeTextDir "es_input.cfg" cfg.inputCfg);
themesDir = let
copyCommands = lib.concatLines (lib.mapAttrsToList (k: v: "cp -r ${v} $out/themes/${k}") cfg.themes);
in pkgs.runCommand "es-themes" {} ''
mkdir -p $out/themes
${copyCommands}
'';
homeDir = pkgs.symlinkJoinSubdir {
name = "es-config-dir";
subdir = ".emulationstation";
paths = [
cfg.systemCfgFile
cfg.inputCfgFile
cfg.settingsCfgFile
cfg.themesDir
] ++ cfg.extraConfigFiles;
};
cli = pkgs.writeShellScript "emulationstation" "${pkgs.emulationstationPatched}/bin/emulationstation --home ${cfg.homeDir} --gamelist-only";
};
};
}