From f5df5eaba6494ddffb2063f38a48ab73f390f97b Mon Sep 17 00:00:00 2001 From: Morgan Jones Date: Sun, 13 Oct 2024 18:35:59 -0700 Subject: [PATCH] dwarf-fortress: purge minor versions and add autoupdate Since DF saves are compatible within the same major version, we can simply keep the latest of each major version. From Dwarf Therapist 42.1.7 onward, dfhack-generated memory maps work in place of Therapist's builtin memory maps. Allow this to happen. --- doc/release-notes/rl-2505.section.md | 2 + pkgs/games/dwarf-fortress/README.md | 9 + pkgs/games/dwarf-fortress/default.nix | 75 ++- pkgs/games/dwarf-fortress/df.lock.json | 107 +++ pkgs/games/dwarf-fortress/dfhack/default.nix | 70 +- .../dwarf-therapist/default.nix | 14 +- .../dwarf-therapist/wrapper.nix | 110 ++- pkgs/games/dwarf-fortress/game.json | 151 ----- pkgs/games/dwarf-fortress/game.nix | 29 +- .../legends-browser/default.nix | 11 +- pkgs/games/dwarf-fortress/themes/default.nix | 1 - pkgs/games/dwarf-fortress/twbt/default.nix | 31 +- pkgs/games/dwarf-fortress/unfuck.nix | 32 - pkgs/games/dwarf-fortress/update.rb | 626 ++++++++++++++++++ pkgs/games/dwarf-fortress/update.sh | 40 -- pkgs/games/dwarf-fortress/wrapper/default.nix | 23 +- .../wrapper/dwarf-fortress-init.in | 2 +- .../dwarf-fortress/wrapper/dwarf-fortress.in | 2 +- 18 files changed, 928 insertions(+), 407 deletions(-) create mode 100644 pkgs/games/dwarf-fortress/README.md create mode 100644 pkgs/games/dwarf-fortress/df.lock.json delete mode 100644 pkgs/games/dwarf-fortress/game.json create mode 100755 pkgs/games/dwarf-fortress/update.rb delete mode 100755 pkgs/games/dwarf-fortress/update.sh diff --git a/doc/release-notes/rl-2505.section.md b/doc/release-notes/rl-2505.section.md index 5fcced82fd4d..7667e0912816 100644 --- a/doc/release-notes/rl-2505.section.md +++ b/doc/release-notes/rl-2505.section.md @@ -207,6 +207,8 @@ - `pnpm` was updated to version 10. If your project is incompatible, you can install the previous version from the package attribute `pnpm_9`. +- `dwarf-fortress-packages` now only contains one minor version for each major version since version 0.44. Saves should still be compatible, but you may have to change which minor version you were using if it was one other than the newest. + - `zig_0_9` and `zig_0_10` have been removed, you should upgrade to `zig_0_13` (also available as just `zig`), `zig_0_12` or `zig_0_11` instead. - `webpack-cli` was updated to major version 6, which has breaking changes from the previous version 5.1.4. See the [upstream release notes](https://github.com/webpack/webpack-cli/releases/tag/webpack-cli%406.0.0) for details on these changes. diff --git a/pkgs/games/dwarf-fortress/README.md b/pkgs/games/dwarf-fortress/README.md new file mode 100644 index 000000000000..210e1f0d0e88 --- /dev/null +++ b/pkgs/games/dwarf-fortress/README.md @@ -0,0 +1,9 @@ +# dwarf-fortress + +Maintainers, please read me! + +The policy for updates is currently keeping one major version of DF around since 0.44. +See [Save Compatibility](https://dwarffortresswiki.org/index.php/Save_compatibility) +on the DF wiki. Note that saves are backwards compatible, but not forwards-compatible. + +This policy has been in effect since Nixpkgs 25.05. diff --git a/pkgs/games/dwarf-fortress/default.nix b/pkgs/games/dwarf-fortress/default.nix index 1929319cf911..492274092554 100644 --- a/pkgs/games/dwarf-fortress/default.nix +++ b/pkgs/games/dwarf-fortress/default.nix @@ -61,12 +61,14 @@ let # out, ensure that (unfuck|dfhack|twbt) are all up to date before changing # this. Note that unfuck and twbt are not required for 50. latestVersion = - if stdenv.hostPlatform.isLinux then - "50.13" - else if stdenv.hostPlatform.isDarwin then - "0.47.05" - else - throw "Unsupported system"; + self.dfVersions.game.latest.${ + if stdenv.hostPlatform.isLinux then + "linux" + else if stdenv.hostPlatform.isDarwin then + "darwin" + else + throw "Unsupported system" + }; # Converts a version to a package name. versionToName = version: "dwarf-fortress_${replaceStrings [ "." ] [ "_" ] version}"; @@ -96,33 +98,50 @@ let stdenv = gccStdenv; }; - dwarf-therapist = libsForQt5.callPackage ./dwarf-therapist/wrapper.nix { - inherit dwarf-fortress; - dwarf-therapist = (libsForQt5.callPackage ./dwarf-therapist { }).override ( - optionalAttrs (!isAtLeast50) { - # 41.2.5 is the last version to support Dwarf Fortress 0.47. - version = "41.2.5"; - hash = "sha256-xfYBtnO1n6OcliVt07GsQ9alDJIfWdVhtuyWwuvXSZs="; + mkDfWrapper = + { + dwarf-fortress, + dfhack, + dwarf-therapist ? null, + ... + }@args: + callPackage ./wrapper ( + { + inherit (self) themes; + inherit + dwarf-fortress + twbt + dfhack + dwarf-therapist + ; + + jdk = jdk8; # TODO: remove override https://github.com/NixOS/nixpkgs/pull/89731 } + // args ); + + dwarf-therapist = libsForQt5.callPackage ./dwarf-therapist/wrapper.nix { + inherit dwarf-fortress dfhack mkDfWrapper; + dwarf-therapist = + (libsForQt5.callPackage ./dwarf-therapist { + inherit (self) dfVersions; + }).override + ( + optionalAttrs (!isAtLeast50) { + # 41.2.5 is the last version to support Dwarf Fortress 0.47. + version = "41.2.5"; + maxDfVersion = "0.47.05"; + hash = "sha256-xfYBtnO1n6OcliVt07GsQ9alDJIfWdVhtuyWwuvXSZs="; + } + ); }; in - callPackage ./wrapper { - inherit (self) themes; - inherit - dwarf-fortress - twbt - dfhack - dwarf-therapist - ; - - jdk = jdk8; # TODO: remove override https://github.com/NixOS/nixpkgs/pull/89731 - }; - }) (attrNames self.df-hashes) + mkDfWrapper { inherit dwarf-fortress dfhack dwarf-therapist; }; + }) (attrNames self.dfVersions.game.versions) ); self = rec { - df-hashes = importJSON ./game.json; + dfVersions = importJSON ./df.lock.json; # Aliases for the latest Dwarf Fortress and the selected Therapist install dwarf-fortress = getAttr (versionToName latestVersion) df-games; @@ -135,9 +154,7 @@ let soundSense = callPackage ./soundsense.nix { }; - legends-browser = callPackage ./legends-browser { - jre = jre8; # TODO: remove override https://github.com/NixOS/nixpkgs/pull/89731 - }; + legends-browser = callPackage ./legends-browser { }; themes = recurseIntoAttrs ( callPackage ./themes { diff --git a/pkgs/games/dwarf-fortress/df.lock.json b/pkgs/games/dwarf-fortress/df.lock.json new file mode 100644 index 000000000000..ff5d22df9714 --- /dev/null +++ b/pkgs/games/dwarf-fortress/df.lock.json @@ -0,0 +1,107 @@ +{ + "game": { + "latest": { + "linux": "51.10", + "darwin": "0.47.05" + }, + "versions": { + "51.10": { + "df": { + "version": "51.10", + "urls": { + "linux": { + "url": "https://www.bay12games.com/dwarves/df_51_10_linux.tar.bz2", + "outputHash": "sha256-r4dadc/nch2smNHt4Ixa2FG2Sc1NFmY88iSnFFeMcz0=" + } + } + }, + "hack": { + "version": "51.10-r1", + "git": { + "url": "https://github.com/DFHack/dfhack.git", + "revision": "51.10-r1", + "outputHash": "sha256-TsgafCiLX/IZXgBdqQaRt7hmATwKz80x2xclCwdE3fM=" + }, + "xmlRev": "ec3ab067aef716817d9c5b84a6fb85bc22516caa" + } + }, + "50.15": { + "df": { + "version": "50.15", + "urls": { + "linux": { + "url": "https://www.bay12games.com/dwarves/df_50_15_linux.tar.bz2", + "outputHash": "sha256-KkKcXfXjD7dUjQDfKtXiaKfoieRN8wJSYxyN6liBwU4=" + } + } + }, + "hack": { + "version": "50.15-r2", + "git": { + "url": "https://github.com/DFHack/dfhack.git", + "revision": "50.15-r2", + "outputHash": "sha256-6T1RXdBJdo/tvHXwYATS8emLIfDg7/0cGL4i982iHdY=" + }, + "xmlRev": "c6c8f15afec05d457813c003a869509901993af4" + } + }, + "0.47.05": { + "df": { + "version": "0.47.05", + "urls": { + "linux": { + "url": "https://www.bay12games.com/dwarves/df_47_05_linux.tar.bz2", + "outputHash": "sha256-rHSm27fX2WIfQwQFCAMiq1DDX2YyNS/y6pI/bcWv/KM=" + }, + "darwin": { + "url": "https://www.bay12games.com/dwarves/df_47_05_osx.tar.bz2", + "outputHash": "sha256-vHmpKtuWSX1ZVGN46MmrLvZ8oiq/vZdjYW3pwuAOXyQ=" + } + } + }, + "hack": { + "version": "0.47.05-r8", + "git": { + "url": "https://github.com/DFHack/dfhack.git", + "revision": "0.47.05-r8", + "outputHash": "sha256-y5XluaNU0ewUg2uAd77+h80CYDwNr1rsxB8IslZWip8=" + }, + "xmlRev": "afe7e908e9e7e863412e8983f9feb2b999fae498" + } + }, + "0.44.12": { + "df": { + "version": "0.44.12", + "urls": { + "linux": { + "url": "https://www.bay12games.com/dwarves/df_44_12_linux.tar.bz2", + "outputHash": "sha256-Wi0Vcw0htBpo2gnOPDtww+Km/RW5XGy/toV47S0tuXk=" + }, + "darwin": { + "url": "https://www.bay12games.com/dwarves/df_44_12_osx.tar.bz2", + "outputHash": "sha256-IY1TGZ9+ufWMA146XUTYgvG2ngfvY/mKZZDWGm/IptU=" + } + } + }, + "hack": { + "version": "0.44.12-r3", + "git": { + "url": "https://github.com/DFHack/dfhack.git", + "revision": "0.44.12-r3", + "outputHash": "sha256-8ChD4P7SpSNlhhOsrbIxoJ/T/CWobwvOY7QswxP0KK0=" + }, + "xmlRev": "4053321b202a29f667d64d824ba8339ec1b1df4f" + } + } + } + }, + "therapist": { + "version": "42.1.12", + "maxDfVersion": "51.10", + "git": { + "url": "https://github.com/Dwarf-Therapist/Dwarf-Therapist.git", + "revision": "v42.1.12", + "outputHash": "sha256-/6tiFjfrAziw7XeEzPoNFgrsXk8Z7ea2PGjCvJlRt+A=" + } + } +} diff --git a/pkgs/games/dwarf-fortress/dfhack/default.nix b/pkgs/games/dwarf-fortress/dfhack/default.nix index 2caa6b9b85af..50f5ec2c9803 100644 --- a/pkgs/games/dwarf-fortress/dfhack/default.nix +++ b/pkgs/games/dwarf-fortress/dfhack/default.nix @@ -24,6 +24,7 @@ binutils, gnused, dfVersion, + dfVersions, }: let @@ -40,77 +41,20 @@ let versionAtLeast ; - dfhack-releases = { - "0.44.10" = { - dfHackRelease = "0.44.10-r2"; - hash = "sha256-0RikMwFv/eJk26Hptnam6J97flekapQhjWvw3+HTfaU="; - xmlRev = "321bd48b10c4c3f694cc801a7dee6be392c09b7b"; - }; - "0.44.11" = { - dfHackRelease = "0.44.11-beta2.1"; - hash = "sha256-Yi/8BdoluickbcQQRbmuhcfrvrl02vf12MuHmh5m/Mk="; - xmlRev = "f27ebae6aa8fb12c46217adec5a812cd49a905c8"; - prerelease = true; - }; - "0.44.12" = { - dfHackRelease = "0.44.12-r1"; - hash = "sha256-3j83wgRXbfcrwPRrJVHFGcLD+tXy1M3MR2dwIw2mA0g="; - xmlRev = "23500e4e9bd1885365d0a2ef1746c321c1dd5094"; - }; - "0.47.02" = { - dfHackRelease = "0.47.02-alpha0"; - hash = "sha256-ScrFcfyiimuLgEaFjN5DKKRaFuKfdJjaTlGDit/0j6Y="; - xmlRev = "23500e4e9bd1885365d0a2ef1746c321c1dd509a"; - prerelease = true; - }; - "0.47.04" = { - dfHackRelease = "0.47.04-r5"; - hash = "sha256-0s+/LKbqsS/mrxKPDeniqykE5+Gy3ZzCa8yEDzMyssY="; - xmlRev = "be0444cc165a1abff053d5893dc1f780f06526b7"; - }; - "0.47.05" = { - dfHackRelease = "0.47.05-r7"; - hash = "sha256-vBKUTSjfCnalkBzfjaIKcxUuqsGGOTtoJC1RHJIDlNc="; - xmlRev = "f5019a5c6f19ef05a28bd974c3e8668b78e6e2a4"; - }; - "50.10" = { - dfHackRelease = "50.10-r1.1"; - hash = "sha256-k2j8G4kJ/RYE8W0YDOxcsRb5qjjn4El+rigf0v3AqZU="; - xmlRev = "041493b221e0799c106abeac1f86df4535ab80d3"; - needsPatches = true; - }; - "50.11" = { - dfHackRelease = "50.11-r7"; - hash = "sha256-3KsFc0i4XkzoeRvcl5GUlx/fJB1HyqfZm+xL6T4oT/A="; - xmlRev = "cca87907c1cbfcf4af957b0bea3a961a345b1581"; - needsPatches = true; - }; - "50.12" = { - dfHackRelease = "50.12-r3"; - hash = "sha256-2mO8DpNmZRCV7IRY0arf3SMvlO4Pxs61Kxfh3q3k3HU="; - xmlRev = "980b1af13acc31660dce632f913c968f52e2b275"; - }; - "50.13" = { - dfHackRelease = "50.13-r3"; - hash = "sha256-WbkJ8HmLT5GdZgDmcuFh+1uzhloKM9um0b9YO//uR7Y="; - xmlRev = "f0530a22149606596e97e3e17d941df3aafe29b9"; - }; - }; - release = if isAttrs dfVersion then dfVersion - else if hasAttr dfVersion dfhack-releases then - getAttr dfVersion dfhack-releases + else if hasAttr dfVersion dfVersions.game.versions then + (getAttr dfVersion dfVersions.game.versions).hack else throw "[DFHack] Unsupported Dwarf Fortress version: ${dfVersion}"; - version = release.dfHackRelease; + inherit (release) version; isAtLeast50 = versionAtLeast version "50.0"; needs50Patches = isAtLeast50 && (release.needsPatches or false); # revision of library/xml submodule - xmlRev = release.xmlRev; + inherit (release) xmlRev; arch = if stdenv.hostPlatform.system == "x86_64-linux" then @@ -149,8 +93,8 @@ stdenv.mkDerivation { src = fetchFromGitHub { owner = "DFHack"; repo = "dfhack"; - rev = release.dfHackRelease; - inherit (release) hash; + tag = release.git.revision; + hash = release.git.outputHash; fetchSubmodules = true; }; diff --git a/pkgs/games/dwarf-fortress/dwarf-therapist/default.nix b/pkgs/games/dwarf-fortress/dwarf-therapist/default.nix index 05cc82297acb..ce41cd2c3398 100644 --- a/pkgs/games/dwarf-fortress/dwarf-therapist/default.nix +++ b/pkgs/games/dwarf-fortress/dwarf-therapist/default.nix @@ -6,8 +6,12 @@ qtdeclarative, cmake, ninja, - version ? "42.1.6", - hash ? "sha256-VjCXT4sl3HsFILrqTc3JJSeRedZaOXUbf4KvSzTo0uc=", + dfVersions, + + # see: https://github.com/Dwarf-Therapist/Dwarf-Therapist/releases + version ? dfVersions.therapist.version, + maxDfVersion ? dfVersions.therapist.maxDfVersion, + hash ? dfVersions.therapist.git.outputHash, }: stdenv.mkDerivation rec { @@ -18,7 +22,7 @@ stdenv.mkDerivation rec { src = fetchFromGitHub { owner = "Dwarf-Therapist"; repo = "Dwarf-Therapist"; - rev = "v${version}"; + tag = "v${version}"; inherit hash; }; @@ -46,6 +50,10 @@ stdenv.mkDerivation rec { dontWrapQtApps = true; + passthru = { + inherit maxDfVersion; + }; + meta = with lib; { mainProgram = "dwarftherapist"; description = "Tool to manage dwarves in a running game of Dwarf Fortress"; diff --git a/pkgs/games/dwarf-fortress/dwarf-therapist/wrapper.nix b/pkgs/games/dwarf-fortress/dwarf-therapist/wrapper.nix index 42da0604567b..62f4b3bdaf91 100644 --- a/pkgs/games/dwarf-fortress/dwarf-therapist/wrapper.nix +++ b/pkgs/games/dwarf-fortress/dwarf-therapist/wrapper.nix @@ -1,10 +1,16 @@ { + lib, stdenv, + writeText, dwarf-therapist, dwarf-fortress, + dfhack, + mkDfWrapper, replaceVars, coreutils, wrapQtAppsHook, + expect, + xvfb-run, }: let @@ -15,12 +21,26 @@ let in prefix + base; inifile = "linux/v0.${builtins.toString dwarf-fortress.baseVersion}.${dwarf-fortress.patchVersion}${platformSlug}.ini"; + unsupportedVersion = lib.versionOlder dwarf-therapist.maxDfVersion dwarf-fortress.dfVersion; + # Used to run dfhack to produce a Therapist ini file for the current memory map. + # See: http://www.bay12forums.com/smf/index.php?topic=168411.msg8532557#msg8532557 + dfHackExpectScript = writeText "dfhack.exp" '' + spawn xvfb-run dfhack +devel/export-dt-ini + expect "DFHack is ready. Have a nice day!" + send "die\r" + ''; + + dfHackWrapper = mkDfWrapper { + inherit dwarf-fortress dfhack; + enableDFHack = true; + }; in stdenv.mkDerivation { pname = "dwarf-therapist"; - inherit (dwarf-therapist) version meta; + inherit (dwarf-therapist) version meta maxDfVersion; + inherit (dwarf-fortress) dfVersion; wrapper = replaceVars ./dwarf-therapist.in { stdenv_shell = "${stdenv.shell}"; @@ -36,37 +56,79 @@ stdenv.mkDerivation { paths = [ dwarf-therapist ]; - nativeBuildInputs = [ wrapQtAppsHook ]; + nativeBuildInputs = + [ wrapQtAppsHook ] + ++ lib.optionals unsupportedVersion [ + expect + xvfb-run + dfHackWrapper + ]; passthru = { inherit dwarf-fortress dwarf-therapist; }; - buildCommand = '' - mkdir -p $out/bin + buildCommand = + lib.optionalString unsupportedVersion '' + fixupMemoryMaps() ( + local output="$1" + local orig_md5="$2" + local patched_md5="$3" + echo "It doesn't support DF $dfVersion out of the box, so we're doing it the hard way." + export NIXPKGS_DF_HOME="$(mktemp -dt dfhack.XXXXXX)" + expect ${dfHackExpectScript} + local ini="$NIXPKGS_DF_HOME/therapist.ini" + if [ -f "$ini" ]; then + if grep -q "$patched_md5" "$ini"; then + cp -v "$ini" "$output" + else + echo "Couldn't find MD5 ($patched_md5) in $ini" + exit 1 + fi + else + echo "Couldn't find $ini!" + exit 1 + fi + ) + '' + + lib.optionalString (!unsupportedVersion) '' + fixupMemoryMaps() { + echo "It should support DF $dfVersion, but we couldn't find any memory maps." + echo "This is a nixpkgs bug, please report it!" + exit 1 + } + '' + + '' + mkdir -p $out/bin - install -Dm755 $wrapper $out/bin/dwarftherapist - ln -s $out/bin/dwarftherapist $out/bin/DwarfTherapist + install -Dm755 $wrapper $out/bin/dwarftherapist + ln -s $out/bin/dwarftherapist $out/bin/DwarfTherapist - substituteInPlace $out/bin/dwarftherapist \ - --subst-var-by install $out - wrapQtApp $out/bin/dwarftherapist + substituteInPlace $out/bin/dwarftherapist \ + --subst-var-by install $out + wrapQtApp $out/bin/dwarftherapist - # Fix up memory layouts - ini_path="$out/share/dwarftherapist/memory_layouts/${inifile}" - rm -f "$ini_path" - mkdir -p "$(dirname -- "$ini_path")" - orig_md5=$(cat "${dwarf-fortress}/hash.md5.orig" | cut -c1-8) - patched_md5=$(cat "${dwarf-fortress}/hash.md5" | cut -c1-8) - input_file="${dwarf-therapist}/share/dwarftherapist/memory_layouts/${inifile}" - output_file="$out/share/dwarftherapist/memory_layouts/${inifile}" + # Fix up memory layouts + input_file="${dwarf-therapist}/share/dwarftherapist/memory_layouts/${inifile}" + output_file="$out/share/dwarftherapist/memory_layouts/${inifile}" + rm -f "$output_file" + mkdir -p "$(dirname -- "$output_file")" - echo "[Dwarf Therapist Wrapper] Fixing Dwarf Fortress MD5 prefix:" - echo " Input: $input_file" - echo " Search: $orig_md5" - echo " Output: $output_file" - echo " Replace: $patched_md5" + orig_md5=$(cat "${dwarf-fortress}/hash.md5.orig" | cut -c1-8) + patched_md5=$(cat "${dwarf-fortress}/hash.md5" | cut -c1-8) - substitute "$input_file" "$output_file" --replace-fail "$orig_md5" "$patched_md5" - ''; + if [ -f "$input_file" ]; then + echo "[Dwarf Therapist Wrapper] Fixing Dwarf Fortress MD5 prefix:" + echo " Input: $input_file" + echo " Search: $orig_md5" + echo " Output: $output_file" + echo " Replace: $patched_md5" + + substitute "$input_file" "$output_file" --replace-fail "$orig_md5" "$patched_md5" + else + echo "[Dwarf Therapist Wrapper] OH NO! No memory maps found!" + echo "This version of Therapist ($dfVersion) has max DF version $maxDfVersion." + fixupMemoryMaps "$output_file" "$orig_md5" "$patched_md5" + fi + ''; preferLocalBuild = true; } diff --git a/pkgs/games/dwarf-fortress/game.json b/pkgs/games/dwarf-fortress/game.json deleted file mode 100644 index 4fb341c350e9..000000000000 --- a/pkgs/games/dwarf-fortress/game.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "0.43.05": { - "linux": "1r0b96yrdf24m9476k5x7rmp3faxr0kfwwdf35agpvlb1qbi6v45", - "linux32": "16l1lydpkbnl3zhz4i2snmjk7pps8vmw3zv0bjgr8dncbsrycd03", - "osx": "1j2zdkjnmxy8yn599pm0qmbi4zjp1m8h4ggqjxhyzp135h0lqqf9", - "osx32": "09ym4mflp5z78pk5mvj7b44xihnsvrxmh0b5kix6h1m6z3cc90l4", - "win": "0m337wh4c47ij1f3zrimvy7baff7nzrmgjbmrwdy89d0z90xpnx8", - "win_s": "0bjk5m1qkn3ldhqiwbq24y2m9fz9r574d54ngdb8b4ri2xfl1fbp", - "win32": "162rl9ygpj66pis87bqc5bwc0mk75hxv6ianhn87pbl4rh7g8ax8", - "win32_s": "0gv1jyw5fdskjjs27pr41grbmkk7ipqn0ry615f5g79k3mhl200i", - "legacy": "09lvbmg1gq257qchlbmq7hxc5nl9r39jpf73zhmwb5xfbpprn0zs", - "legacy_s": "023a5b27fm65w7gmzjssyyci70fdjk2zbv965y4n0f23kc4rj9gl", - "legacy32": "1m75arxj1q82l2dkk8qcargm3xczxlqi8krwvg3iimddky34gipq", - "legacy32_s": "1hgzsk66isfr5vcraxwgl7cvycl14kwf8w9kzxr8jyp5z7k24q29" - }, - "0.44.05": { - "linux": "18bjyhjp5458bfbizm8vq4s00pqpfs097qp6pv76m84kgbc4ghg3", - "linux32": "1b9i4kf4c8s6bhqwn8jx100mg7fqp8nmswrai5w8dsma01py4amr", - "osx": "1ssc8vq3ad38x9c04j8gg96kxv0g2npi3jwcg40676byx5nrx7b6", - "osx32": "12i7x8idcbvp5h62jyc7b7j98jf4lrisnwglvnrms6jclj0b3g0q", - "win": "1kaifarjx0akg7s5a2ngfw0vm0vyr4jnax5rrbv96dliqn5knddz", - "win_s": "1a1xikrjdv4b0yfgnp5s8d6xn0njylynsqd8zixdc01vccl5kqm6", - "win32": "1j3cq0h7jdvxbsbpfxa7bli45smvy9m4fji0j6849kj7x0vcpwq4", - "win32_s": "10cw1n48ffkrv9ms07ka5b5370d9k2fm051cnnq03lkcvlwrq145", - "legacy": "0y7xpgmwn4nshhc7apyf8mj5ycl0q5vckdaviwzz6w1x31s3dp6n", - "legacy_s": "0j8rbw9ww1avmh8zhyzljjj6in87q4qffpffdl394fsi74n8px0d", - "legacy32": "0d3l4jvx53a01fjf1lf20ar9lfyykfhk05dlrfwz3w4k7vj4vvlf", - "legacy32_s": "1c5x9x44bblz7anhmk4y9a7p1b39b9k7gzvj4pi55jzfq0k60kl7" - }, - "0.44.09": { - "linux": "1haikynkg1pqyrzzqk1qxm19p36ww58qp8brh3fjxssp4x71rcdy", - "linux32": "0lmbrdf7wjdwj5yx0khnq871yxvhfwqxjjyfkqcdy5ik18lvlkj8", - "osx": "01dss8g9lmi8majp6lxcfw166ydz4himkz6am5pi29gixaf4vfqs", - "osx32": "1iwlvmz1ir9k0kzn6726frmkznvsg9a99bbqnxvwcnq3nnnjxw3s", - "win": "08g5irgp59dfjgj3jxc8ixwzgnz2wghcl8cg1b1g4088dsf2x3x8", - "win_s": "1xyb4msn9wfrh7x136r8xn3sjz6z8c4zksbzifa0z0bpa3pdviap", - "win32": "0m8bs2mnyi1r4x84fwnfgd1ijdcf08xsq5zy84476svci932g5kz", - "win32_s": "0pl319qmyy96ibzlgj4wfj19dv1wzyg8ig6q11l4c7rivzc9286i", - "legacy": "0l8nrvppfzazhjsfkd5nd0bxnc6ljk8fs6yg8qh69g7q7zvzgnd3", - "legacy_s": "1c49z539a31czzq0rnhg6yrv1zbaja35sd0ssr4k7lsghjv84k1z", - "legacy32": "155xg6dpb8frlw7d9h7m1y0spw55wl4nkn7zrm70bpyp39pydlqp", - "legacy32_s": "05qkzjfx1ybrv96wya1dirdfxdkhj6a440sjpzwbqpkqgr8z57a3" - }, - "0.44.10": { - "linux": "1cqm43hn3ar9d8a7y7dwq48ajp72cirn1gclh8r2fykkypprxmp2", - "linux32": "0gdb6sq8725nwdisxwha8f5b6arq570s73aj4gdrh611gxh13r6n", - "osx": "1wpa45d81q8f5mhqmaxvdkz93k6cm3pg7vpsqjjjsp5s961gd74g", - "osx32": "0rsy1n19n12gh8rddgi3db32in488f2nizq8kw25hga03hsh4r6x", - "win": "04i0ka12hmn3chsyfmk2pbknr1pdf3p8yaz7kv82ri4g6dvsjfv6", - "win_s": "01m6nqcrz4rhdc8wb31azj3vmjid8bdpqaf9wkz4g4vvjyy7xiyz", - "win32": "1nymin8wbzbh8gm2702dy7h5spdijdxnysdz71ldyl0xx4vw68d9", - "win32_s": "1skz0jpfm6j9bins04kn96f3v3k0kvjqlh25x3129r3hh8xacnd3", - "legacy": "0s84vpfr2b5y1kda9allqjrpkaxw15mkblk9dq08syhsj19vspa7", - "legacy_s": "18b7ikp7xy2y071h3ydfh5mq9hw9y303rdqyikvra5ji3n5p96cm", - "legacy32": "1yh2fl3qwpy6wrxavhn75grbjygymnfh746hxbmc60la7y5flrpy", - "legacy32_s": "0j65w2hxgpccg9qsaz14r82qvnvfd0pbl2gyx9fv8d77kxhkc4pw" - }, - "0.44.11": { - "linux": "1qizfkxl2k6pn70is4vz94q4k55bc3pm13b2r6yqi6lw1cnna4sf", - "linux32": "11m39lfyrsxlw1g7f269q7fzwichg06l21fxhqzgvlvmzmxsf8q5", - "osx": "073hmcj7bm323m3xqi42605rkvmgmv83bnxz1byymgs8aqyfykkx", - "osx32": "0w5avnj86wprk8q0rb5qm9kxbigzk6dk0akqbw4m76jgg2jdmir7", - "win": "1yxyv1sycn5jc3g1y02d82154xydg3kbghis7l3xi28n3bh8387b", - "win_s": "1xzwl6c362wqgps911y9q8vndp8zyd20fc2p7pkzzmw2hrgfqi6q", - "win32": "16x2rg3gm3lh2akg7n057kkxxigb2ljz0nk685lmn4j0adq8l31p", - "win32_s": "1a2y220111d94mzj5y3jwpy062k8fw25akyp7yn3fwa17vwvn8zq", - "legacy": "0gfjmsfqj21hs4d1hm7fvppbdjspc4r2qnnp6mwcbgh67i5p5rdb", - "legacy_s": "1wr4hpzmhgl8haric3jpfd3kwqv1fi4vkb1gvaax5f7kplvfqfac", - "legacy32": "1cpzckwvqkxqn0c498mmh4papsjdi3mcvcp2vzlvj46kvdl3n0f0", - "legacy32_s": "024vzwfcrx7ms4dip0ccwd0vizzck2pwz2ryyvlz4rpjzhswj5gi" - }, - "0.44.12": { - "win32": "0bxrc7zj4vgcgdwc130g6f5jnp13vgx9a2kn2l1jcc958x8a367g", - "linux32": "0fmr8diskmbh12s0bpfn5gky9lmrc7xxj6va5adjm6ahxv9jwr06", - "osx": "1md6r1pimmlhcn5gjqzg0ygbdwc2v125sfjy0f6gbfbykwcm7391", - "osx32": "1dbg7pavxw20r8iqc566fn558avgj5glsycvi6ggbvsh0rpw6n5v", - "win": "0zb5ximqi5j7vyvgjzfz7ycadh5sgb7jlyaa68x0sjlbybdr1min", - "win_s": "1ncf5zr1fggr5knf30l0wh7spp376v1jcc6m9c86zim8azcfx0y7", - "linux": "0ydr5lnysy45nsznqp5r2pysdqn3f0xkrkh9v9l1md111mriabas", - "win32_s": "1mxbjkikf010skrpng51r86jmv4nal51j5n1y9kyhv344bq6chr9", - "legacy": "11a212ynhx18p3k8hvdjx199din14wggxiwz191b4309fznzpprz", - "legacy_s": "05madj529y18ndxrih96mivbzng1vz2zbzicrcnj58i2084zm23f", - "legacy32": "0rapcydiic2nq6idjf7fg53xsxk8dxzyi1vflpz554ghdrnsmwjv", - "legacy32_s": "16fgbd3lx4r270dxqj6gr1g1iqjj8cv389h2hw1l646xx28g8d2m" - }, - "0.47.01": { - "linux": "1wbybkfpgvpd2yliy8mfgddnz806ac4rv4j0lhlsqwpk8jj0mx81", - "linux32": "1fnz1mydqgybcm8kzranvjzc2x9g6bcalxv3fsjngvpv13x6izzv", - "osx": "18wdffidasbrsbhqjwds08ckbrjhcw0759aynz7zggyy5is9q8iw", - "osx32": "1b4kf3vg0zd5w5s0rdhzfz0rswkl6sq0j1f8qmimnw7qd09h43wx", - "win": "1v3v2z7g67d6926h9lxakznvbddyxyr85i1ym34y2wywnc886z7r", - "win_s": "0yahynimhz4nvdi5qp5a612vf7ikg87w2aj2r8s1lhdw6xwdkpyc", - "win32": "07mqhm64c1ddjc3vpyhf9qf14lp19xwz3pgg4c2pvcwy4yyrys22", - "win32_s": "07acbxai8g04yxg7n68nyx4jwcqqkgjn7n96q2lzxdvc988kiivz", - "legacy32_s": "1gxmc3rsl9glai3wb4wzsda3qyhdimd8s5kbr5m753n8lmzasafx" - }, - "0.47.02": { - "linux": "1zbsygbfiqxxs767qxkxjp3ayywi5q0d8xlrqlbd0l8a3ccg5avw", - "linux32": "1ddc9s4n408j8gidgign51bgv2wgy5z4cy74jzx00pvnhsfp2mpy", - "osx": "1mwy88yxip1wys1kxpfsbg7wlvfrkc4lg04gqw0d266a88dj7a30", - "osx32": "08ssnzl52gqqgcqhl0ynyikbxz76825kpcg1d6yx8g7ifjndf19n", - "win": "08g7fy18y8q32l0158314bny0qg57xz37qj9fri9r4xbhci67ldk", - "win_s": "0x56s1md62yk661aqcdgnz8k0zir0zr8qwan5vrqc0q9yh069yl1", - "win32": "0ww64mymbilb235n93d7w4c9axq3ww2mxa0f7bl4x8yrxwc8k942", - "win32_s": "0r801vip807v88icf47i3s82v7lshx67q4ilzfjirqfslh1x00bs", - "legacy": "14f4d6r7swfjnlaalg4l5916ihj6wvhlsgjp7cygamzp4c2wgng8", - "legacy_s": "1jxf52kaijf4crwxj30a4f6z7rzs6xa91y6vn5s8jr0cvbr5pz64", - "legacy32": "0j7shqdv3gimacj03cil2y0fmr0j0fp57cwmdjwnxwx3m96k3xwm", - "legacy32_s": "1wc7pcp9dwz0q1na3i5pbqknya595qdkmr7hsmgh2kk8rsp3g9g2" - }, - "0.47.04": { - "linux": "1ri82c5hja6n0wv538srf2nbcyb8ip49w4l201m90cmcycmqgr8x", - "linux32": "00yz8gl75sbx15d7vl22ij0a5qd325kpc9mgm1lh5g7i065vgzn8", - "osx": "0c1g655bn5n4pbzxw3v83gmy54va5y87m7ksi6iryfal0m9lshhv", - "osx32": "1knfgqbwa7v9va1w6i8yzz6xp3dj633dbs50izx6ldszm0ra42pg", - "win": "0j7ixr3rf9900zzfw3nd3vg97kdkspm530cmf9dkwhf6klmpks7s", - "win_s": "11amw5gjhi753mvf17wifcjiyikjx0qwa16787gfhj9jfp0yw764", - "win32": "1xw9f49n85c31kbzkm5zh81kccjx9msjyy3xwr0klak5w398a59l", - "win32_s": "0s26hrgfk2b5wg4dvg90wgw1mvrrvbyjhmsys9f5fl7zn1pjbxxr", - "legacy": "103bcnn8gxi2rkpjmjfgv5a5kxmh1zd7vagrsscv55sppd7fcl7n", - "legacy_s": "19ai7lvxx0y3iha9qrbl5krric547rzs6vm4ibk8x61vv97jrbd8", - "legacy32": "0lli6s1g7yj3p3h26ajgq3h619n88qn6s7amyz6z8w7hyzfi7wij", - "legacy32_s": "1wzxbzgln9pmsk2nchrl94d2yd09xdgynmjl4qwcaqzkrnf3sfqc" - }, - "0.47.05": { - "linux": "18zwmz2nsgwjxbr2yd9jcrgw6l5b481hh1848cgn5nfpnzdscx5c", - "linux32": "1jbav7ghsjsxd6cdp6f2x5qn83zc8707dqan5sp73fp6mbj2jasl", - "osx": "092z1vhc5sbdc5irggdz5ai7rxifmg4yhy33aicpsjcnvcmajydw", - "osx32": "0lpbwfiagp0zp280aw3fmj8938w5fc5r9gibzk2h86jy63ps29ww", - "win": "0bbk7j3d4h2wn9hmbsbbbbr0ajf3ddlprxfaajfbnbiyv72cpn9s", - "win_s": "0nl7c9dpfx7jjpy7y52z8h3kiy4cpax1m58apbcfyy95an4jz8s4", - "win32": "08ka1lklly82h4mr770y9p0a21x9dx6jqvjgxdsxj5979f26il1v", - "win32_s": "06w844zxzx3lfykibgkk4gbg4xymnqraj1ikv4mzlv31l727a1x4", - "legacy": "042a0gbad3cp5dwhnrzg3vr9w48b8ybqgxgw5i9rk4c1i0gjjpw2", - "legacy_s": "1rb7h8lzlsjs08rvhhl3nwbrpj54zijijp4y0qdp4vyzsig6nisk", - "legacy32": "0ayw09x9smihh8qp5pdvr6vvhwkvcqz36h3lh4g1b5kzxj7g9cyf", - "legacy32_s": "10gfxlysfs9gyi1mv52idp5xk45g9h517g2jq4a8cqp2j7594v9c" - }, - "50.10": { - "linux": "13s5p7205r9ha2j5n7carrwd0y7krq34bcdl08khp0kh2v4470a3" - }, - "50.11": { - "linux": "0iz2d88gzvn0vjxlr99f13j4awhvh2lggjmipdwpbxhfsqih7dx0" - }, - "50.12": { - "linux": "070014fzwszfgjyxjyij0k0hadah6s62lpi91ykp3vs220azya1m" - }, - "50.13": { - "linux": "19wzgsdgv0vq7v2dxhypr9hayky3nm3lbra1kk9vn8ri96jdkfkw" - } -} diff --git a/pkgs/games/dwarf-fortress/game.nix b/pkgs/games/dwarf-fortress/game.nix index b394cd991635..61a0ee31039c 100644 --- a/pkgs/games/dwarf-fortress/game.nix +++ b/pkgs/games/dwarf-fortress/game.nix @@ -15,7 +15,7 @@ gcc, dfVersion, - df-hashes, + dfVersions, }: let @@ -35,14 +35,9 @@ let ; # Map Dwarf Fortress platform names to Nixpkgs platform names. - # Other srcs are available like 32-bit mac & win, but I have only - # included the ones most likely to be needed by Nixpkgs users. platforms = { x86_64-linux = "linux"; - i686-linux = "linux32"; - x86_64-darwin = "osx"; - x86_64-cygwin = "win"; - i686-cygwin = "win32"; + x86_64-darwin = "darwin"; }; dfVersionTuple = splitVersion dfVersion; @@ -61,8 +56,8 @@ let && (dwarf-fortress-unfuck.dfVersion or null) == dfVersion; game = - if hasAttr dfVersion df-hashes then - getAttr dfVersion df-hashes + if hasAttr dfVersion dfVersions.game.versions then + (getAttr dfVersion dfVersions.game.versions).df else throw "Unknown Dwarf Fortress version: ${dfVersion}"; dfPlatform = @@ -70,9 +65,9 @@ let getAttr stdenv.hostPlatform.system platforms else throw "Unsupported system: ${stdenv.hostPlatform.system}"; - sha256 = - if hasAttr dfPlatform game then - getAttr dfPlatform game + url = + if hasAttr dfPlatform game.urls then + getAttr dfPlatform game.urls else throw "Unsupported dfPlatform: ${dfPlatform}"; exe = @@ -87,8 +82,8 @@ stdenv.mkDerivation { version = dfVersion; src = fetchurl { - url = "https://www.bay12games.com/dwarves/df_${toString baseVersion}_${toString patchVersion}_${dfPlatform}.tar.bz2"; - inherit sha256; + inherit (url) url; + hash = url.outputHash; }; sourceRoot = "."; @@ -184,7 +179,11 @@ stdenv.mkDerivation { dfVersion exe ; - updateScript = ./update.sh; + updateScript = { + command = [ ./update.rb ]; + attrPath = "dwarf-fortress-packages"; + supportedFeatures = [ "commit" ]; + }; }; meta = { diff --git a/pkgs/games/dwarf-fortress/legends-browser/default.nix b/pkgs/games/dwarf-fortress/legends-browser/default.nix index f6fdfc4c5c6c..a4aab7863c26 100644 --- a/pkgs/games/dwarf-fortress/legends-browser/default.nix +++ b/pkgs/games/dwarf-fortress/legends-browser/default.nix @@ -8,11 +8,11 @@ let name = "legends-browser-${version}"; - version = "1.17.1"; + version = "1.19.2"; jar = fetchurl { url = "https://github.com/robertjanetzko/LegendsBrowser/releases/download/${version}/legendsbrowser-${version}.jar"; - sha256 = "05b4ksbl4481rh3ykfirbp6wvxhppcd5mvclhn9995gsrcaj8gx9"; + hash = "sha256-jkv7InwaRn0K3VAa0LqkYpH6TnrT/tGYBtbvNGM6t98="; }; script = writeShellScriptBin "legends-browser" '' @@ -24,7 +24,7 @@ let echo 'Creating initial configuration for legends-browser' echo "last=$(cd ..; pwd)" > legendsbrowser.properties fi - ${jre}/bin/java -jar ${jar} + exec ${jre}/bin/java -jar ${jar} ''; in @@ -34,7 +34,10 @@ buildEnv { meta = with lib; { description = "Multi-platform, open source, java-based legends viewer for dwarf fortress"; - maintainers = with maintainers; [ Baughn ]; + maintainers = with maintainers; [ + Baughn + numinit + ]; sourceProvenance = with sourceTypes; [ binaryBytecode ]; license = licenses.mit; platforms = platforms.all; diff --git a/pkgs/games/dwarf-fortress/themes/default.nix b/pkgs/games/dwarf-fortress/themes/default.nix index befcd224a060..a37e07557a23 100644 --- a/pkgs/games/dwarf-fortress/themes/default.nix +++ b/pkgs/games/dwarf-fortress/themes/default.nix @@ -7,7 +7,6 @@ let listToAttrs maintainers platforms - readFile ; in diff --git a/pkgs/games/dwarf-fortress/twbt/default.nix b/pkgs/games/dwarf-fortress/twbt/default.nix index 7b56ab310e8b..85cca0998fbc 100644 --- a/pkgs/games/dwarf-fortress/twbt/default.nix +++ b/pkgs/games/dwarf-fortress/twbt/default.nix @@ -16,37 +16,16 @@ let ; twbt-releases = { - "0.44.10" = { - twbtRelease = "6.49"; - sha256 = "1qjkc7k33qhxj2g18njzasccjqsis5y8zrw5vl90h4rs3i8ld9xz"; - prerelease = false; - }; - "0.44.11" = { - twbtRelease = "6.51"; - sha256 = "1yclqmarjd97ch054h425a12r8a5ailmflsd7b39cg4qhdr1nii5"; - prerelease = true; - }; "0.44.12" = { twbtRelease = "6.54"; - sha256 = "10gfd6vv0vk4v1r5hjbz7vf1zqys06dsad695gysc7fbcik2dakh"; + hash = "sha256-cKomZmTLHab9K8k0pZsB2uMf3D5/SVhy2GRusLdp7oE="; prerelease = false; }; - "0.47.02" = { - twbtRelease = "6.61"; - sha256 = "07bqy9rkd64h033sxdpigp5zq4xrr0xd36wdr1b21g649mv8j6yw"; - prerelease = false; - }; - "0.47.04" = { - twbtRelease = "6.xx"; - dfhackRelease = "0.47.04-r5"; - sha256 = "sha256-+C3g4KJShCb2VXGQ4mtkDOufXZQ1P+ebDTmUzL3tNyU="; - prerelease = true; - }; "0.47.05" = { twbtRelease = "6.xx"; - dfhackRelease = "0.47.05-r7"; - sha256 = "sha256-4xMKuSP5J6pMK+hwjTAcTI0gsLJfw+Xt+vh9CopR4tk="; - prerelease = true; + dfhackRelease = "0.47.05-r8"; + hash = "sha256-qiNs6iMAUNGiq0kpXqEs4u4Wcrjf6/qA/dzBe947Trc="; + prerelease = false; }; }; @@ -67,7 +46,7 @@ stdenvNoCC.mkDerivation rec { "https://github.com/thurin/df-twbt/releases/download/${release.dfhackRelease}/twbt-${version}-linux64-${release.dfhackRelease}.zip" else "https://github.com/mifki/df-twbt/releases/download/v${version}/twbt-${version}-linux.zip"; - sha256 = release.sha256; + inherit (release) hash; }; sourceRoot = "."; diff --git a/pkgs/games/dwarf-fortress/unfuck.nix b/pkgs/games/dwarf-fortress/unfuck.nix index b04c2132cec6..d679eb4d0a3a 100644 --- a/pkgs/games/dwarf-fortress/unfuck.nix +++ b/pkgs/games/dwarf-fortress/unfuck.nix @@ -32,42 +32,10 @@ let ; unfuck-releases = { - "0.43.05" = { - unfuckRelease = "0.43.05"; - hash = "sha256-4iLVrKmlVdvBICb8NLe/U7pHtL372CGDkxt/2lf2bZw="; - }; - "0.44.05" = { - unfuckRelease = "0.44.05"; - hash = "sha256-iwR9st4VsPJBn7cKH/cy8YS6Tcw8J+lMJK9/9Qgl0gM="; - }; - "0.44.09" = { - unfuckRelease = "0.44.09"; - hash = "sha256-9W9qON0QEjfXe2XzRvseixc+YznPzDQdcId08dEGF40="; - }; - "0.44.10" = { - unfuckRelease = "0.44.10"; - hash = "sha256-8ldEFcf5zPRdC/yXgMByeCC0pqZprreITIetKDpOYW0="; - }; - "0.44.11" = { - unfuckRelease = "0.44.11.1"; - hash = "sha256-f9vDe3Q3Vl2hFLCPSzYtqyv9rLKBKEnARZTu0MKaX88="; - }; "0.44.12" = { unfuckRelease = "0.44.12"; hash = "sha256-f9vDe3Q3Vl2hFLCPSzYtqyv9rLKBKEnARZTu0MKaX88="; }; - "0.47.01" = { - unfuckRelease = "0.47.01"; - hash = "sha256-k8yrcJVHlHNlmOL2kEPTftSfx4mXO35TcS0zAvFYu4c="; - }; - "0.47.02" = { - unfuckRelease = "0.47.01"; - hash = "sha256-k8yrcJVHlHNlmOL2kEPTftSfx4mXO35TcS0zAvFYu4c="; - }; - "0.47.04" = { - unfuckRelease = "0.47.04"; - hash = "sha256-KRr0A/2zANAOSDeP8V9tYe7tVO2jBLzU+TF6vTpISfE="; - }; "0.47.05" = { unfuckRelease = "0.47.05-final"; hash = "sha256-kBdzU6KDpODOBP9XHM7lQRIEWUGOj838vXF1FbSr0Xw="; diff --git a/pkgs/games/dwarf-fortress/update.rb b/pkgs/games/dwarf-fortress/update.rb new file mode 100755 index 000000000000..d722d7a4b326 --- /dev/null +++ b/pkgs/games/dwarf-fortress/update.rb @@ -0,0 +1,626 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i ruby -p "ruby.withPackages (ps: with ps; [ curb nokogiri ])" nix-prefetch-git + +require 'set' +require 'json' +require 'uri' +require 'shellwords' +require 'erb' +require 'rubygems' +require 'curb' +require 'nokogiri' + +# Performs a GET to an arbitrary address. +# +url+:: the URL +def get url, &block + curl = Curl::Easy.new(url) do |http| + http.follow_location = false + http.headers['User-Agent'] = 'nixpkgs dwarf fortress update bot' + yield http if block_given? + end + + curl.perform + curl.body_str +end + +# Performs a GET on the Github API. +# +url+:: the relative URL to api.github.com +def get_gh url, &block + ret = get URI.join('https://api.github.com/', url) do |http| + http.headers['Accept'] = 'application/vnd.github+json' + http.headers['Authorization'] = "Bearer #{ENV['GH_TOKEN']}" if ENV.include?('GH_TOKEN') + http.headers['X-GitHub-Api-Version'] = '2022-11-28' + yield http if block_given? + end + JSON.parse(ret, symbolize_names: true) +end + +def normalize_keys hash + Hash[hash.map { + [ + _1.to_s, + _2.is_a?(Hash) ? normalize_keys(_2) : _2 + ] + }] +end + +module Mergeable + # Merges this Mergeable with something else. + # +other+:: The other Mergeable. + def merge other + if !other + return self + end + + if !other.is_a?(Mergeable) || self.members != other.members + raise "invalid right-hand operand for merge: #{other.members}" + end + + hash = {} + self.members.each do |member| + if @@expensive && @@expensive.include?(member) + # Already computed + hash[member] = self[member] + elsif self[member] && self[member].is_a?(Mergeable) + # Merge it + hash[member] = self[member].merge(other[member]) + elsif self[member] && self[member].is_a?(Hash) + hash[member] = Hash[other[member].map { + [_1, self[member][_1] && self[member][_1].is_a?(Mergeable) ? self[member][_1].merge(_2) : _2] + }] + else + # Compute it + hash[member] = other[member] + end + end + self.class.new(**hash) + end + + # Marks some attributes as expensive. + def expensive *attrs + @@expensive ||= Set.new + attrs.each {@@expensive << _1} + self + end +end + +module Versionable + # Parses the version. + def parsed_version + @version ||= Gem::Version.create(self.version.partition('-').first) + end + + # Drops the last component of the version for chunking. + def major_version + @major_version ||= Gem::Version.create(self.parsed_version.canonical_segments[..-2].join('.')) + end + + # Compares the major version. + def =~ other + self.major_version == other.major_version + end + + # Negation of the above. + def !~ other + !(self =~ other) + end + + # Compares two versions. + def <=> other + other.parsed_version <=> self.parsed_version + end +end + +class DFUrl < Struct.new(:url, :output_hash, keyword_init: true) + include Mergeable + extend Mergeable + + expensive :output_hash + + # Converts this DFUrl to a hash. + def to_h + { + url: self.url, + outputHash: self.output_hash + } + end + + # Returns or computes the output hash. + def output_hash + return super if super + self.output_hash = `nix-prefetch-url #{Shellwords.escape(self.url.to_s)} | xargs nix-hash --to-sri --type sha256`.strip + super + end + + # Converts this DFUrl from a hash. + # +hash+:: The hash + def self.from_hash hash + DFUrl.new( + url: hash.fetch(:url), + output_hash: hash[:outputHash] + ) + end +end + +class DFGithub < Struct.new(:url, :revision, :output_hash, keyword_init: true) + include Mergeable + extend Mergeable + + expensive :output_hash + + # Converts this DFGithub to a hash. + def to_h + { + url: self.url, + revision: self.revision, + outputHash: self.output_hash + } + end + + # Returns or computes the output hash. + def output_hash + return super if super + url = URI.parse(self.url.to_s) + if ENV['GH_TOKEN'] + url.userinfo = ENV['GH_TOKEN'] + end + self.output_hash = JSON.parse(`nix-prefetch-git --no-deepClone --fetch-submodules #{Shellwords.escape(url.to_s)} #{Shellwords.escape(self.revision.to_s)}`, symbolize_names: true).fetch(:hash) + super + end + + # Converts a hash to a DFGithub. + # +hash+:: The hash + def self.from_hash hash + DFGithub.new( + url: hash.fetch(:url), + revision: hash.fetch(:revision), + output_hash: hash[:outputHash] + ) + end +end + +class DFVersion < Struct.new(:version, :urls, keyword_init: true) + include Mergeable + extend Mergeable + include Versionable + + # Converts a DFVersion to a hash. + def to_h + { + version: self.version, + urls: Hash[self.urls.map { + [_1, _2.to_h] + }] + } + end + + # Converts a hash to a DFVersion. + # +hash+:: The hash + def self.from_hash hash + DFVersion.new( + version: hash.fetch(:version), + urls: Hash[hash.fetch(:urls).map { + [_1, DFUrl.from_hash(_2)] + }] + ) + end + + # Converts an HTML node to a DFVersion. + # +base+:: The base URL for DF downloads. + # +node+:: The HTML node + def self.from_node base, node + match = node.text.match(/DF\s+(\d+\.\d+(?:\.\d+)?)/) + if match + systems = {} + node.css('a').each do |a| + case a['href'] + when /osx\.tar/ then systems[:darwin] = DFUrl.new(url: URI.join(base, a['href']).to_s) + when /linux\.tar/ then systems[:linux] = DFUrl.new(url: URI.join(base, a['href']).to_s) + end + end + + if systems.empty? + nil + else + DFVersion.new(version: match[1], urls: systems) + end + else + nil + end + end + + # Returns all DFVersions from the download page. + # +cutoff+:: The minimum version + def self.all cutoff: + cutoff = Gem::Version.create(cutoff) + + base = 'https://www.bay12games.com/dwarves/' + res = get URI.join(base, 'older_versions.html') + parsed = Nokogiri::HTML(res) + + # Figure out which versions we care about. + parsed.css('p.menu').map {DFVersion.from_node(base, _1)}.select { + _1 && _1.parsed_version >= cutoff + }.sort.chunk { + _1.major_version + }.map {|*, versions| + versions.max_by {_1.parsed_version} + }.to_a + end +end + +class DFHackVersion < Struct.new(:version, :git, :xml_rev, keyword_init: true) + include Mergeable + extend Mergeable + include Versionable + + expensive :xml_rev + + # Returns the download URL. + def git + return super if super + self.git = DFGithub.new( + url: "https://github.com/DFHack/dfhack.git", + revision: self.version + ) + super + end + + # Converts this DFHackVersion to a hash. + def to_h + { + version: self.version, + git: self.git.to_h, + xmlRev: self.xml_rev, + } + end + + # Returns the revision number in the version. Defaults to 0. + def rev + return @rev if @rev + rev = self.version.match(/-r([\d\.]+)\z/) + @rev = rev[1].to_f if rev + @rev ||= 0 + @rev + end + + # Returns the XML revision, fetching it if necessary. + def xml_rev + return super if super + url = "repos/dfhack/dfhack/contents/library/xml?ref=#{URI.encode_uri_component(self.git.revision)}" + body = get_gh url + self.xml_rev = body.fetch(:sha) + super + end + + # Compares two DFHack versions. + # +other+:: the other dfhack version + def <=> other + ret = super + ret = other.rev <=> self.rev if ret == 0 + ret + end + + # Returns a version from a hash. + # +hash+:: the hash + def self.from_hash hash + DFHackVersion.new( + version: hash.fetch(:version), + git: DFGithub.from_hash(hash.fetch(:git)), + xml_rev: hash[:xmlRev] + ) + end + + # Returns a release from a github object. + # +github_obj+:: The github object. Returns null for prereleases. + def self.from_github github_obj + if github_obj.fetch(:prerelease) + return nil + end + version = github_obj.fetch(:tag_name) + DFHackVersion.new(version: version) + end + + # Returns all dfhack versions. + # +cutoff+:: The cutoff version. + def self.all cutoff: + cutoff = Gem::Version.create(cutoff) + ret = {} + (1..).each do |page| + url = "repos/dfhack/dfhack/releases?per_page=100&page=#{page}" + releases = get_gh url + + releases.each do |release| + release = DFHackVersion.from_github(release) + if release && release.parsed_version >= cutoff + ret[release.major_version] ||= {} + ret[release.major_version][release.parsed_version] ||= [] + ret[release.major_version][release.parsed_version] << release + end + end + + break if releases.length < 1 + end + + ret.each do |_, dfhack_major_versions| + dfhack_major_versions.each do |_, dfhack_minor_versions| + dfhack_minor_versions.sort! + end + end + + ret + end +end + +class DFWithHackVersion < Struct.new(:df, :hack, keyword_init: true) + include Mergeable + extend Mergeable + + # Converts this DFWithHackVersion to a hash. + def to_h + { + df: self.df.to_h, + hack: self.hack.to_h + } + end + + # Converts a hash to a DFWithHackVersion. + # +hash+:: the hash to convert + def self.from_hash hash + DFWithHackVersion.new( + df: DFVersion.from_hash(hash.fetch(:df)), + hack: DFHackVersion.from_hash(hash.fetch(:hack)) + ) + end +end + +class DFWithHackVersions < Struct.new(:latest, :versions, keyword_init: true) + include Mergeable + extend Mergeable + + # Initializes this DFWithHackVersions. + def initialize *args, **kw + super *args, **kw + self.latest ||= {} + self.versions ||= {} + end + + # Converts this DFWithHackVersions to a hash. + def to_h + { + latest: self.latest, + versions: Hash[self.versions.map { + [_1.to_s, _2.to_h] + }] + } + end + + # Loads this DFWithHackVersions. + # +cutoff+:: The minimum version to load. + def load! cutoff: + df_versions = DFVersion.all(cutoff: cutoff) + dfhack_versions = DFHackVersion.all(cutoff: cutoff) + + df_versions.each do |df_version| + latest_dfhack_version = nil + corresponding_dfhack_versions = dfhack_versions.dig(df_version.major_version, df_version.parsed_version) + if corresponding_dfhack_versions + latest_dfhack_version = corresponding_dfhack_versions.first + end + + if latest_dfhack_version + df_version.urls.each do |platform, url| + if !self.latest[platform] || df_version.parsed_version > Gem::Version.create(self.latest[platform]) + self.latest[platform] = df_version.version + end + end + self.versions[df_version.version] = DFWithHackVersion.new(df: df_version, hack: latest_dfhack_version) + end + end + end + + # Converts a hash to a DFWithHackVersions. + # +hash+:: The hash + def self.from_hash hash + DFWithHackVersions.new( + latest: hash.fetch(:latest), + versions: Hash[hash.fetch(:versions).map { + [_1.to_s, DFWithHackVersion.from_hash(_2)] + }] + ) + end +end + +class Therapist < Struct.new(:version, :max_df_version, :git, keyword_init: true) + include Mergeable + extend Mergeable + include Versionable + + expensive :max_df_version + + # Converts this Therapist instance to a hash. + def to_h + { + version: self.version, + maxDfVersion: self.max_df_version, + git: self.git.to_h + } + end + + # Returns the max supported DF version. + def max_df_version + return super if super + url = "repos/Dwarf-Therapist/Dwarf-Therapist/contents/share/memory_layouts/linux?ref=#{URI.encode_uri_component(self.git.revision)}" + body = get_gh url + + # Figure out the max supported memory layout. + max_version = nil + max_version_str = nil + body.each do |item| + name = item[:name] || "" + match = name.match(/\Av(?:0\.)?(\d+\.\d+)-classic_linux\d*\.ini/) + if match + version = Gem::Version.create(match[1]) + if !max_version || version > max_version + max_version = version + max_version_str = match[1] + end + end + end + + self.max_df_version = max_version_str + + super + end + + # Returns a Github URL. + def git + return super if super + self.git = DFGithub.new( + url: "https://github.com/Dwarf-Therapist/Dwarf-Therapist.git", + revision: 'v' + self.version + ) + super + end + + # Loads this therapist instance from Github. + def load! + latest = self.class.latest + self.version = latest.version + self.max_df_version = latest.max_df_version + self.git = nil + self + end + + # Loads a hash into this Therapist instance. + # +hash+: the hash + def self.from_hash hash + Therapist.new( + version: hash.fetch(:version), + max_df_version: hash[:maxDfVersion], + git: DFGithub.from_hash(hash.fetch(:git)) + ) + end + + # Returns a release from a github object. + # +github_obj+:: The github object. Returns null for prereleases. + def self.from_github github_obj + if github_obj.fetch(:prerelease) + return nil + end + + version = github_obj.fetch(:tag_name) + match = version.match(/\Av([\d\.]+)\z/) + if match + Therapist.new(version: match[1]) + else + nil + end + end + + # Returns the latest Therapist version. + def self.latest + url = "repos/Dwarf-Therapist/Dwarf-Therapist/releases" + releases = get_gh url + + releases.each do |release| + release = Therapist.from_github(release) + if release + return release + end + end + + nil + end +end + +class DFLock < Struct.new(:game, :therapist, keyword_init: true) + include Mergeable + extend Mergeable + + # Initializes this DFLock. + def initialize *args, **kw + super *args, **kw + self.game ||= DFWithHackVersions.new + self.therapist ||= Therapist.new + end + + # Converts this DFLock to a hash. + def to_h + { + game: self.game.to_h, + therapist: self.therapist.to_h + } + end + + # Returns an array containing all versions. + def all_versions + self.game.versions.keys.map {"DF #{_1}"}.to_a + ["DT #{self.therapist.version}"] + end + + # Loads this DFLock. + # +cutoff+:: The minimum DF version to load. + def load! cutoff: + self.game.load! cutoff: cutoff + self.therapist.load! + end + + # Converts a hash to a DFLock. + # +hash+:: The hash + def self.from_hash hash + DFLock.new( + game: DFWithHackVersions.from_hash(hash.fetch(:game)), + therapist: Therapist.from_hash(hash.fetch(:therapist)) + ) + end +end + +# 0.43 and below has a broken dfhack. +new_df_lock = DFLock.new +new_df_lock.load! cutoff: '0.44' + +df_lock_file = File.join(__dir__, 'df.lock.json') +df_lock, df_lock_json = if File.file?(df_lock_file) + json = JSON.parse(File.read(df_lock_file), symbolize_names: true) + [DFLock.from_hash(json), json] + else + [DFLock.new, {}] + end + +new_df_lock_json = df_lock.merge(new_df_lock).to_h +json = JSON.pretty_generate(new_df_lock_json) +json << "\n" +STDERR.puts json +File.write(df_lock_file, json) + +# See if there were any changes. +changed_paths = [] +if normalize_keys(df_lock_json) != normalize_keys(new_df_lock_json) + all_old_versions = df_lock.all_versions + all_new_versions = new_df_lock.all_versions + just_old_versions = all_old_versions - all_new_versions + just_new_versions = all_new_versions - all_old_versions + changes = just_old_versions.zip(just_new_versions) + + template = ERB.new(<<-EOF, trim_mode: '<>-') +dwarf-fortress-packages: <%= changes.map {|old, new| '%s -> %s' % [old, new]}.join('; ') %> + +Performed the following automatic DF updates: + +<% changes.each do |old, new| %> +- <%= old -%> -> <%= new -%> +<% end %> +EOF + + changed_paths << { + attrPath: 'dwarf-fortress-packages', + oldVersion: just_old_versions.join('; '), + newVersion: just_new_versions.join('; '), + files: [ + File.realpath(df_lock_file) + ], + commitMessage: template.result(binding) + } +end + +STDOUT.puts JSON.pretty_generate(changed_paths) diff --git a/pkgs/games/dwarf-fortress/update.sh b/pkgs/games/dwarf-fortress/update.sh deleted file mode 100755 index 892e031f7883..000000000000 --- a/pkgs/games/dwarf-fortress/update.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env nix-shell -#! nix-shell -i bash -p jq nix coreutils curl - -# systems to generate hashes for -systems='linux osx' - -if [ $# -eq 0 ]; then - versions="$(curl http://www.bay12games.com/dwarves/ \ - | grep 'DWARF FORTRESS CLASSIC ' \ - | sed 's/.*DWARF FORTRESS CLASSIC \([0-9.]*\) .*/\1/')" -else - versions="$@" -fi - -tmp1="$(mktemp)" -tmp2="$(mktemp)" -for version in $versions; do - for system in $systems; do - echo -n $version,$system, - ver=$(echo $version | sed -e s,^0\.,, | tr . _) - if [[ "$system" = *win* ]] || [[ "$system" = *legacy* ]]; then - ext=zip - else - ext=tar.bz2 - fi - nix-prefetch-url \ - http://www.bay12games.com/dwarves/df_${ver}_${system}.${ext} - done -done | jq --slurp --raw-input \ - 'split("\n") | .[:-1] | map(split(",")) | - map({ "version": .[0], "platform": .[1], "sha256": .[2] }) | - group_by(.version) | - map(map({"version": .version, (.platform): .sha256}) | add | - {(.version): .} | map_values(del(.version))) | add' \ - > "$tmp1" - -# Append $tmp1 to game.json. There should be a better way to handle -# this but all other attempts failed for me. -jq -M --slurpfile a "$tmp1" '. + $a[]' < "$(dirname "$0")/game.json" > "$tmp2" -cat "$tmp2" > "$(dirname "$0")/game.json" diff --git a/pkgs/games/dwarf-fortress/wrapper/default.nix b/pkgs/games/dwarf-fortress/wrapper/default.nix index 55f08c328558..372467475321 100644 --- a/pkgs/games/dwarf-fortress/wrapper/default.nix +++ b/pkgs/games/dwarf-fortress/wrapper/default.nix @@ -246,28 +246,17 @@ lib.throwIf (enableTWBT' && !enableDFHack) "dwarf-fortress: TWBT requires DFHack installCheckPhase = let - commonExpectStatements = - fmod: - lib.optionalString isAtLeast50 '' - expect "Loading audio..." - '' - + lib.optionalString (!fmod && isAtLeast50) '' - expect "Failed to load fmod, trying SDL_mixer" - '' - + lib.optionalString isAtLeast50 '' - expect "Audio loaded successfully!" - '' - + '' - expect "Loading bindings from data/init/interface.txt" - ''; + commonExpectStatements = '' + expect "Loading bindings from data/init/interface.txt" + ''; dfHackExpectScript = writeText "dfhack-test.exp" ( '' spawn env NIXPKGS_DF_OPTS=debug xvfb-run $env(out)/bin/dfhack '' - + commonExpectStatements false + + commonExpectStatements + '' expect "DFHack is ready. Have a nice day!" - expect "DFHack version ${version}" + expect "DFHack version ${dfhack'.version}" expect "\[DFHack\]#" send -- "lua print(os.getenv('out'))\r" expect "$env(out)" @@ -281,7 +270,7 @@ lib.throwIf (enableTWBT' && !enableDFHack) "dwarf-fortress: TWBT requires DFHack '' spawn env NIXPKGS_DF_OPTS=debug,${lib.optionalString fmod "fmod"} xvfb-run $env(out)/bin/dwarf-fortress '' - + commonExpectStatements fmod + + commonExpectStatements + '' exit 0 '' diff --git a/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress-init.in b/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress-init.in index 1c739a1afbbf..363585fac293 100644 --- a/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress-init.in +++ b/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress-init.in @@ -114,7 +114,7 @@ go() { # If we make it past here, we want to log. # shellcheck disable=SC2093 - exec -a "$NIXPKGS_DF_EXE" "$NIXPKGS_DF_HOME/$NIXPKGS_DF_EXE" + exec -a "$NIXPKGS_DF_EXE" "$NIXPKGS_DF_HOME/$NIXPKGS_DF_EXE" "$@" log "Execution of $NIXPKGS_DF_HOME/$NIXPKGS_DF_EXE failed!" exit 1 } diff --git a/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress.in b/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress.in index 29db9c128f4c..9616936f0705 100644 --- a/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress.in +++ b/pkgs/games/dwarf-fortress/wrapper/dwarf-fortress.in @@ -32,4 +32,4 @@ else done fi -go +go "$@"