diff --git a/pkgs/games/minecraft-server/default.nix b/pkgs/games/minecraft-server/default.nix index 02054f1ad8b5..f1ab122ffe0e 100644 --- a/pkgs/games/minecraft-server/default.nix +++ b/pkgs/games/minecraft-server/default.nix @@ -1,40 +1,17 @@ -{ lib, stdenv, fetchurl, nixosTests, jre_headless }: -stdenv.mkDerivation { - pname = "minecraft-server"; - version = "1.18.1"; +{ callPackage, lib }: +# if you add more versions make sure to add to all-packages.nix +let + versions = lib.importJSON ./versions.json; + latestVersion = lib.last (builtins.sort lib.versionOlder (builtins.attrNames versions)); + escapeVersion = builtins.replaceStrings [ "." ] [ "_" ]; - src = fetchurl { - url = "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar"; - # sha1 because that comes from mojang via api - sha1 = "125e5adf40c659fd3bce3e66e67a16bb49ecc1b9"; - }; - - preferLocalBuild = true; - - installPhase = '' - mkdir -p $out/bin $out/lib/minecraft - cp -v $src $out/lib/minecraft/server.jar - - cat > $out/bin/minecraft-server << EOF - #!/bin/sh - exec ${jre_headless}/bin/java \$@ -jar $out/lib/minecraft/server.jar nogui - EOF - - chmod +x $out/bin/minecraft-server - ''; - - dontUnpack = true; - - passthru = { - tests = { inherit (nixosTests) minecraft-server; }; - updateScript = ./update.sh; - }; - - meta = with lib; { - description = "Minecraft Server"; - homepage = "https://minecraft.net"; - license = licenses.unfreeRedistributable; - platforms = platforms.unix; - maintainers = with maintainers; [ thoughtpolice tomberek costrouc ]; - }; + packages = lib.mapAttrs' + (version: value: { + name = "minecraft-server_${escapeVersion version}"; + value = callPackage ./derivation.nix { inherit (value) version url sha1; }; + }) + versions; +in +packages // { + minecraft-server = builtins.getAttr "minecraft-server_${escapeVersion latestVersion}" packages; } diff --git a/pkgs/games/minecraft-server/derivation.nix b/pkgs/games/minecraft-server/derivation.nix new file mode 100644 index 000000000000..8f0d5a02a838 --- /dev/null +++ b/pkgs/games/minecraft-server/derivation.nix @@ -0,0 +1,36 @@ +{ lib, stdenv, fetchurl, nixosTests, jre_headless, version, url, sha1 }: +stdenv.mkDerivation { + pname = "minecraft-server"; + inherit version; + + src = fetchurl { inherit url sha1; }; + + preferLocalBuild = true; + + installPhase = '' + mkdir -p $out/bin $out/lib/minecraft + cp -v $src $out/lib/minecraft/server.jar + + cat > $out/bin/minecraft-server << EOF + #!/bin/sh + exec ${jre_headless}/bin/java \$@ -jar $out/lib/minecraft/server.jar nogui + EOF + + chmod +x $out/bin/minecraft-server + ''; + + dontUnpack = true; + + passthru = { + tests = { inherit (nixosTests) minecraft-server; }; + updateScript = ./update.py; + }; + + meta = with lib; { + description = "Minecraft Server"; + homepage = "https://minecraft.net"; + license = licenses.unfreeRedistributable; + platforms = platforms.unix; + maintainers = with maintainers; [ thoughtpolice tomberek costrouc ]; + }; +} diff --git a/pkgs/games/minecraft-server/update.py b/pkgs/games/minecraft-server/update.py new file mode 100755 index 000000000000..ef54bcae6d4c --- /dev/null +++ b/pkgs/games/minecraft-server/update.py @@ -0,0 +1,147 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i python3 -p python3Packages.requests python3Packages.dataclasses-json + +import json +from dataclasses import dataclass, field +from datetime import datetime +from typing import Any, Dict, List, Optional + +import requests +from dataclasses_json import DataClassJsonMixin, LetterCase, config +from marshmallow import fields + + +@dataclass +class Download(DataClassJsonMixin): + sha1: str + size: int + url: str + + +@dataclass +class Version(DataClassJsonMixin): + id: str + type: str + url: str + time: datetime = field( + metadata=config( + encoder=datetime.isoformat, + decoder=datetime.fromisoformat, + mm_field=fields.DateTime(format="iso"), + ) + ) + release_time: datetime = field( + metadata=config( + encoder=datetime.isoformat, + decoder=datetime.fromisoformat, + mm_field=fields.DateTime(format="iso"), + letter_case=LetterCase.CAMEL, + ) + ) + + def get_manifest(self) -> Any: + """Return the version's manifest.""" + response = requests.get(self.url) + response.raise_for_status() + return response.json() + + def get_downloads(self) -> Dict[str, Download]: + """ + Return all downloadable files from the version's manifest, in Download + objects. + """ + return { + download_name: Download.from_dict(download_info) + for download_name, download_info in self.get_manifest()["downloads"].items() + } + + def get_server(self) -> Optional[Download]: + """ + If the version has a server download available, return the Download + object for the server download. If the version does not have a server + download avilable, return None. + """ + downloads = self.get_downloads() + if "server" in downloads: + return downloads["server"] + return None + + +def get_versions() -> List[Version]: + """Return a list of Version objects for all available versions.""" + response = requests.get( + "https://launchermeta.mojang.com/mc/game/version_manifest.json" + ) + response.raise_for_status() + data = response.json() + return [Version.from_dict(version) for version in data["versions"]] + + +def get_major_release(version_id: str) -> str: + """ + Return the major release for a version. The major release for 1.17 and + 1.17.1 is 1.17. + """ + if not len(version_id.split(".")) >= 2: + raise ValueError(f"version not in expected format: '{version_id}'") + return ".".join(version_id.split(".")[:2]) + + +def group_major_releases(releases: List[Version]) -> Dict[str, List[Version]]: + """ + Return a dictionary containing each version grouped by each major release. + The key "1.17" contains a list with two Version objects, one for "1.17" + and another for "1.17.1". + """ + groups: Dict[str, List[Version]] = {} + for release in releases: + major_release = get_major_release(release.id) + if major_release not in groups: + groups[major_release] = [] + groups[major_release].append(release) + return groups + + +def get_latest_major_releases(releases: List[Version]) -> Dict[str, Version]: + """ + Return a dictionary containing the latest version for each major release. + The latest major release for 1.16 is 1.16.5, so the key "1.16" contains a + Version object for 1.16.5. + """ + return { + major_release: sorted(releases, key=lambda x: x.id, reverse=True)[0] + for major_release, releases in group_major_releases(releases).items() + } + + +def generate() -> Dict[str, Dict[str, str]]: + """ + Return a dictionary containing the latest url, sha1 and version for each major + release. + """ + versions = get_versions() + releases = list( + filter(lambda version: version.type == "release", versions) + ) # remove snapshots and betas + latest_major_releases = get_latest_major_releases(releases) + + servers = { + version: Download.schema().dump(download_info) # Download -> dict + for version, download_info in { + version: value.get_server() + for version, value in latest_major_releases.items() + }.items() + if download_info is not None # versions < 1.2 do not have a server + } + for server in servers.values(): + del server["size"] # don't need it + + for version, server in servers.items(): + server["version"] = latest_major_releases[version].id + return servers + + +if __name__ == "__main__": + with open("versions.json", "w") as file: + json.dump(generate(), file, indent=2) + file.write("\n") diff --git a/pkgs/games/minecraft-server/update.sh b/pkgs/games/minecraft-server/update.sh deleted file mode 100755 index 433a12a9caf6..000000000000 --- a/pkgs/games/minecraft-server/update.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -i bash -p curl jq common-updater-scripts - -BASEDIR="$(dirname "$0")" - -# get current release version -versions=$(curl -s 'https://launchermeta.mojang.com/mc/game/version_manifest.json') -version=$(echo $versions | jq .latest.release) -url=$(echo $versions | jq -r ".versions[] | select(.id == $version) | .url") - -# get current server.jar -versions=$(curl -s $url | jq .downloads.server) -sha1=$(echo $versions | jq .sha1) -url=$(echo $versions | jq .url) - -echo $version: $url:$sha1 - -# change default.nix -sed -i "s/version = \"[0-9.]*\";/version = ${version};/g" "$BASEDIR/default.nix" -sed -i "s+url = \"[a-zA-Z0-9/:.]*/server.jar\";+url = $url;+g" "$BASEDIR/default.nix" -sed -i "s/sha1 = \"[a-zA-Z0-9]*\";/sha1 = ${sha1};/g" "$BASEDIR/default.nix" diff --git a/pkgs/games/minecraft-server/versions.json b/pkgs/games/minecraft-server/versions.json new file mode 100644 index 000000000000..238f8af9eef0 --- /dev/null +++ b/pkgs/games/minecraft-server/versions.json @@ -0,0 +1,87 @@ +{ + "1.18": { + "url": "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar", + "sha1": "125e5adf40c659fd3bce3e66e67a16bb49ecc1b9", + "version": "1.18.1" + }, + "1.17": { + "url": "https://launcher.mojang.com/v1/objects/a16d67e5807f57fc4e550299cf20226194497dc2/server.jar", + "sha1": "a16d67e5807f57fc4e550299cf20226194497dc2", + "version": "1.17.1" + }, + "1.16": { + "url": "https://launcher.mojang.com/v1/objects/1b557e7b033b583cd9f66746b7a9ab1ec1673ced/server.jar", + "sha1": "1b557e7b033b583cd9f66746b7a9ab1ec1673ced", + "version": "1.16.5" + }, + "1.15": { + "url": "https://launcher.mojang.com/v1/objects/bb2b6b1aefcd70dfd1892149ac3a215f6c636b07/server.jar", + "sha1": "bb2b6b1aefcd70dfd1892149ac3a215f6c636b07", + "version": "1.15.2" + }, + "1.14": { + "url": "https://launcher.mojang.com/v1/objects/3dc3d84a581f14691199cf6831b71ed1296a9fdf/server.jar", + "sha1": "3dc3d84a581f14691199cf6831b71ed1296a9fdf", + "version": "1.14.4" + }, + "1.13": { + "url": "https://launcher.mojang.com/v1/objects/3737db93722a9e39eeada7c27e7aca28b144ffa7/server.jar", + "sha1": "3737db93722a9e39eeada7c27e7aca28b144ffa7", + "version": "1.13.2" + }, + "1.12": { + "url": "https://launcher.mojang.com/v1/objects/886945bfb2b978778c3a0288fd7fab09d315b25f/server.jar", + "sha1": "886945bfb2b978778c3a0288fd7fab09d315b25f", + "version": "1.12.2" + }, + "1.11": { + "url": "https://launcher.mojang.com/v1/objects/f00c294a1576e03fddcac777c3cf4c7d404c4ba4/server.jar", + "sha1": "f00c294a1576e03fddcac777c3cf4c7d404c4ba4", + "version": "1.11.2" + }, + "1.10": { + "url": "https://launcher.mojang.com/v1/objects/3d501b23df53c548254f5e3f66492d178a48db63/server.jar", + "sha1": "3d501b23df53c548254f5e3f66492d178a48db63", + "version": "1.10.2" + }, + "1.9": { + "url": "https://launcher.mojang.com/v1/objects/edbb7b1758af33d365bf835eb9d13de005b1e274/server.jar", + "sha1": "edbb7b1758af33d365bf835eb9d13de005b1e274", + "version": "1.9.4" + }, + "1.8": { + "url": "https://launcher.mojang.com/v1/objects/b58b2ceb36e01bcd8dbf49c8fb66c55a9f0676cd/server.jar", + "sha1": "b58b2ceb36e01bcd8dbf49c8fb66c55a9f0676cd", + "version": "1.8.9" + }, + "1.7": { + "url": "https://launcher.mojang.com/v1/objects/4cec86a928ec171fdc0c6b40de2de102f21601b5/server.jar", + "sha1": "4cec86a928ec171fdc0c6b40de2de102f21601b5", + "version": "1.7.9" + }, + "1.6": { + "url": "https://launcher.mojang.com/v1/objects/050f93c1f3fe9e2052398f7bd6aca10c63d64a87/server.jar", + "sha1": "050f93c1f3fe9e2052398f7bd6aca10c63d64a87", + "version": "1.6.4" + }, + "1.5": { + "url": "https://launcher.mojang.com/v1/objects/f9ae3f651319151ce99a0bfad6b34fa16eb6775f/server.jar", + "sha1": "f9ae3f651319151ce99a0bfad6b34fa16eb6775f", + "version": "1.5.2" + }, + "1.4": { + "url": "https://launcher.mojang.com/v1/objects/2f0ec8efddd2f2c674c77be9ddb370b727dec676/server.jar", + "sha1": "2f0ec8efddd2f2c674c77be9ddb370b727dec676", + "version": "1.4.7" + }, + "1.3": { + "url": "https://launcher.mojang.com/v1/objects/3de2ae6c488135596e073a9589842800c9f53bfe/server.jar", + "sha1": "3de2ae6c488135596e073a9589842800c9f53bfe", + "version": "1.3.2" + }, + "1.2": { + "url": "https://launcher.mojang.com/v1/objects/d8321edc9470e56b8ad5c67bbd16beba25843336/server.jar", + "sha1": "d8321edc9470e56b8ad5c67bbd16beba25843336", + "version": "1.2.5" + } +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 5a010ae9f29e..91683111a354 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -30810,7 +30810,25 @@ with pkgs; minecraft = callPackage ../games/minecraft { }; - minecraft-server = callPackage ../games/minecraft-server { }; + inherit (import ../games/minecraft-server { inherit callPackage lib; }) + minecraft-server_1_2 + minecraft-server_1_3 + minecraft-server_1_4 + minecraft-server_1_5 + minecraft-server_1_6 + minecraft-server_1_7 + minecraft-server_1_8 + minecraft-server_1_9 + minecraft-server_1_10 + minecraft-server_1_11 + minecraft-server_1_12 + minecraft-server_1_13 + minecraft-server_1_14 + minecraft-server_1_15 + minecraft-server_1_16 + minecraft-server_1_17 + minecraft-server_1_18 + minecraft-server; moon-buggy = callPackage ../games/moon-buggy {};