diff --git a/.gitignore b/.gitignore index cb4e2fd..4922455 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /nixos.qcow2 -/emulationstation-source +result +result-* diff --git a/games.nix b/games.nix index 561f520..c8c00d8 100644 --- a/games.nix +++ b/games.nix @@ -1,25 +1,13 @@ -{ - retronix.emulationstation = { +{pkgs, ...}: { + retronix = { systems = { - "Arcade" = { - command = "bash -c 'echo $XINIT'"; - games = [ - { - src = ./emulationstation/roms/Arcade/atetris.zip; - filename = "atetris.zip"; - name = "Tetris"; - desc = "Tetris, le classique des jeux de puzzle que tout le monde connait (et auquel tout le monde joue quand on met les affaires dans le coffre en partant en vacances). Tetris est devenu un phénomène mondial lorsqu'il a été vendu en pack avec l'achat de la Gameboy originale, en 1989. L'OST est célèbre, avec ses origines classiques russes qui sont maintenant célèbres. "; - rating = "0.9"; - releasedate = "19880101T000000"; - developer = "bootleg"; - publisher = "Atari"; - genre = "Puzzle-Game"; - players = "1-2"; - } - ]; + "Arcade" = { + extension = ".sh"; + games = with pkgs.roms; [ + atetris + ]; + }; }; - + emulationstation.inputCfg = builtins.readFile ./es_input.cfg; }; - inputCfg = builtins.readFile ./es_input.cfg; -}; } diff --git a/launch_es.sh b/launch_es.sh new file mode 100755 index 0000000..32a9ef0 --- /dev/null +++ b/launch_es.sh @@ -0,0 +1,5 @@ +export NIXPKGS_ALLOW_UNFREE=1 + +RESULT=$(nix-build -E 'import ((import ./npins).nixpkgs + "/nixos")' -A config.retronix.emulationstation.cli -I nixos-config=configuration.nix --no-out-link $@) + +$RESULT diff --git a/build.sh b/launch_vm.sh similarity index 77% rename from build.sh rename to launch_vm.sh index cc66251..847de9c 100755 --- a/build.sh +++ b/launch_vm.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash -RESULT=$(nix-build -E 'import ((import ./npins).nixpkgs + "/nixos")' -A config.system.build.vm -I nixos-config=configuration.nix --no-out-link --option substituters "" $@) +export NIXPKGS_ALLOW_UNFREE=1 + +RESULT=$(nix-build -E 'import ((import ./npins).nixpkgs + "/nixos")' -A config.system.build.vm -I nixos-config=configuration.nix --no-out-link $@) $RESULT/bin/run-nixos-vm diff --git a/modules/es-config.nix b/modules/es-config.nix index 8010ee9..89fc967 100644 --- a/modules/es-config.nix +++ b/modules/es-config.nix @@ -6,22 +6,29 @@ let attrToXml = attrs: lib.concatLines (lib.mapAttrsToList (k: v: "<${k}>${builtins.toString v}") attrs); - gameTemplate = args: let + gameTemplate = game: let attr = [ "path" "name" + "sortname" "desc" "image" - "thumbnail" "video" + "marquee" + "thumbnail" "rating" "releasedate" "developer" "publisher" "genre" "players" - "sortname" + "favorite" + "hidden" + "kidgame" + "playcount" + "lastplayed" ]; + args = game.meta // { path = "@out@/${game.name}.sh"; }; in '' ${attrToXml (filterAttrs' attr args)} @@ -52,7 +59,7 @@ let ''; symlinkCommands = builtins.map ( - v: "ln -s ${v.src} $out/${v.filename}" + v: "ln -s ${v}/${v.launchPath} $out/${v.name}.sh" ) games; in pkgs.runCommand "${name}-roms" { @@ -63,7 +70,7 @@ let } '' mkdir -p $out cp $gamelistPath $out/gamelist.xml - substituteInPlace $out/gamelist.xml --subst-var out + substituteAllInPlace $out/gamelist.xml ${lib.concatLines symlinkCommands} ''; @@ -79,19 +86,18 @@ let type = lib.types.str; default = name; }; - path = lib.mkOption { # TODO: check it works + path = lib.mkOption { type = lib.types.path; }; command = lib.mkOption { type = lib.types.str; - default = "echo \"Hello world !\""; + default = "%ROM%"; }; extension = lib.mkOption { type = lib.types.str; - default = ".zip"; }; games = lib.mkOption { - type = lib.types.listOf gameOptions; + type = lib.types.listOf lib.types.package; description = "Takes attributes of `games` tag in gamelist.xml"; }; }; @@ -99,90 +105,64 @@ let path = mkSystemPath config.name config.games; }; }); - - gameOptions = lib.types.submodule ({config, name, ... }: { - freeformType = with lib.types; attrsOf str; - options = { - src = lib.mkOption { - type = lib.types.path; - }; - name = lib.mkOption { - type = lib.types.str; - }; - desc = lib.mkOption { - type = lib.types.str; - default = ""; - }; - path = lib.mkOption { - type = lib.types.str; - default = "@out@/${config.filename}"; - }; - filename = lib.mkOption { - type = lib.types.str; - }; - }; - }); in { options = { - retronix.emulationstation = { + retronix = { + emulationstation = { + systemCfgFile = lib.mkOption { + type = lib.types.path; + }; + inputCfgFile = lib.mkOption { + type = lib.types.path; + }; + themesDir = lib.mkOption { + type = lib.types.path; + }; + 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 = {}; }; - systemCfgFile = lib.mkOption { - type = lib.types.path; - }; - inputCfgFile = lib.mkOption { - type = lib.types.path; - }; - systemsDir = lib.mkOption { - internal = true; - type = lib.types.path; - description = "Directory containing the symlinks to roms and gamelists.xml files"; - }; - themesDir = lib.mkOption { - type = lib.types.path; - }; - 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. - Must contain .emulationstation folder - ''; - }; - cli = lib.mkOption { - type = lib.types.str; - }; }; }; config = { retronix.emulationstation = { - systemCfgFile = writeESDir "es_systems.cfg" '' + systemCfgFile = pkgs.writeTextDir "es_systems.cfg" '' - ${lib.concatLines (lib.mapAttrsToList (_: systemTemplate) cfg.systems)} + ${lib.concatLines (lib.mapAttrsToList (_: systemTemplate) config.retronix.systems)} ''; - inputCfgFile = lib.mkDefault (writeTextDir "es_input.cfg" cfg.inputCfg); - homeDir = pkgs.symlinkJoinSubDir { + inputCfgFile = lib.mkDefault (pkgs.writeTextDir "es_input.cfg" cfg.inputCfg); + homeDir = pkgs.symlinkJoinSubdir { name = "es-config-dir"; + subdir = ".emulationstation"; paths = [ cfg.systemCfgFile cfg.inputCfgFile ] ++ cfg.extraConfigFiles; }; - cli = t "${pkgs.emulationstation}/bin/emulationstation --home ${cfg.homeDir}"; + cli = pkgs.writeScript "emulationstation" "${pkgs.emulationstationPatched}/bin/emulationstation --home ${cfg.homeDir} --gamelist-only"; }; }; diff --git a/pkgs/overlay.nix b/pkgs/overlay.nix index b0a12c0..cad8642 100644 --- a/pkgs/overlay.nix +++ b/pkgs/overlay.nix @@ -1,11 +1,15 @@ final: prev: { - joy2keyd = final.python3.pkgs.callPackage ./joy2keyd {}; retropieSetup = final.callPackage ./retropie-setup.nix {}; + + joy2keyd = final.python3.pkgs.callPackage ./joy2keyd {}; joy2key = final.callPackage ./joy2key.nix {}; + runcommand = final.callPackage ./runcommand.nix {}; + emulationstationPatched = final.emulationstation.overrideAttrs (_: previous: { patches = [ ./emulationstation.patch ]; }); + symlinkJoinSubdir = args_@{ name , paths @@ -29,4 +33,6 @@ final: prev: { done ${postBuild} ''; + + roms = final.callPackage ./roms {}; } diff --git a/pkgs/roms/atetris.nix b/pkgs/roms/atetris.nix new file mode 100644 index 0000000..6003f7d --- /dev/null +++ b/pkgs/roms/atetris.nix @@ -0,0 +1,18 @@ +{mkRetroarchRom}: +mkRetroarchRom { + name = "Tetris"; + src = ./bin/atetris; + + emulator = "mame"; + filename = "atetris.zip"; + + meta = { + desc = "Tetris, le classique des jeux de puzzle que tout le monde connait (et auquel tout le monde joue quand on met les affaires dans le coffre en partant en vacances). Tetris est devenu un phénomène mondial lorsqu'il a été vendu en pack avec l'achat de la Gameboy originale, en 1989. L'OST est célèbre, avec ses origines classiques russes qui sont maintenant célèbres. "; + rating = "0.9"; + releasedate = "19880101T000000"; + developer = "bootleg"; + publisher = "Atari"; + genre = "Puzzle-Game"; + players = "1-2"; + }; +} diff --git a/pkgs/roms/build/mkRetroarchRom.nix b/pkgs/roms/build/mkRetroarchRom.nix new file mode 100644 index 0000000..0fcd40d --- /dev/null +++ b/pkgs/roms/build/mkRetroarchRom.nix @@ -0,0 +1,19 @@ +{ mkRom , retroarchFull }: +{ name +, src +, emulator +, filename +, settings ? {} +, meta +}: +let + retroarch = retroarchFull.override (prev: { + settings = prev.settings // settings; + }); +in +mkRom ({ + runtimeInputs = [ retroarch ]; + # To do add a check for the emulator + command = "retroarch -L ${emulator} ${builtins.placeholder "out"}/usr/share/${filename}"; + inherit meta src name; +}) diff --git a/pkgs/roms/build/mkRom.nix b/pkgs/roms/build/mkRom.nix new file mode 100644 index 0000000..2254db8 --- /dev/null +++ b/pkgs/roms/build/mkRom.nix @@ -0,0 +1,54 @@ +{ runCommand, runtimeShell, stdenv, shellcheck-minimal, lib, lndir }: +{ name +, src +, runtimeInputs ? [ ] +, command +, meta ? {} +}: +runCommand name { + inherit meta src; + allowSubstitutes = true; + preferLocalBuild = false; + + launchPath = "launch.sh"; + + script = '' + #!${runtimeShell} + set -o errexit + set -o nounset + set -o pipefail + '' + lib.optionalString (runtimeInputs != [ ]) '' + + export PATH="${lib.makeBinPath runtimeInputs}:$PATH" + '' + '' + + ${command} + ''; + + passAsFile = [ "script" ]; + + checkPhase = '' + runHook preCheck + ${stdenv.shellDryRun} "$target" + ${lib.getExe shellcheck-minimal} "$target" + runHook postCheck + ''; + +} '' + target=$out/bin/${lib.escapeShellArg name} + rom_dir=$out/usr/share + + mkdir -p "$(dirname "$target")" + mkdir -p "$rom_dir" + + # symlink rom_dir + ${lndir}/bin/lndir $src $rom_dir + + mv "$scriptPath" "$target" + chmod +x "$target" + + # symlink the executable to help emulation station calls + ln -s $target $out/$launchPath + + eval "$checkPhase" +'' diff --git a/pkgs/roms/default.nix b/pkgs/roms/default.nix new file mode 100644 index 0000000..e41cc36 --- /dev/null +++ b/pkgs/roms/default.nix @@ -0,0 +1,12 @@ +{ lib, newScope }: + +let + romsFun = self: let + inherit (self) callPackage; + in { + atetris = callPackage ./atetris.nix {}; + + mkRom = callPackage ./build/mkRom.nix {}; + mkRetroarchRom = callPackage ./build/mkRetroarchRom.nix {}; + }; +in lib.makeScope newScope romsFun