minecraft-server: package major versions

authored by Joel and committed by tomberek 867b8e21 ae02cde6

+304 -60
+15 -38
pkgs/games/minecraft-server/default.nix
··· 1 - { lib, stdenv, fetchurl, nixosTests, jre_headless }: 2 - stdenv.mkDerivation { 3 - pname = "minecraft-server"; 4 - version = "1.18.1"; 1 + { callPackage, lib }: 2 + # if you add more versions make sure to add to all-packages.nix 3 + let 4 + versions = lib.importJSON ./versions.json; 5 + latestVersion = lib.last (builtins.sort lib.versionOlder (builtins.attrNames versions)); 6 + escapeVersion = builtins.replaceStrings [ "." ] [ "_" ]; 5 7 6 - src = fetchurl { 7 - url = "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar"; 8 - # sha1 because that comes from mojang via api 9 - sha1 = "125e5adf40c659fd3bce3e66e67a16bb49ecc1b9"; 10 - }; 11 - 12 - preferLocalBuild = true; 13 - 14 - installPhase = '' 15 - mkdir -p $out/bin $out/lib/minecraft 16 - cp -v $src $out/lib/minecraft/server.jar 17 - 18 - cat > $out/bin/minecraft-server << EOF 19 - #!/bin/sh 20 - exec ${jre_headless}/bin/java \$@ -jar $out/lib/minecraft/server.jar nogui 21 - EOF 22 - 23 - chmod +x $out/bin/minecraft-server 24 - ''; 25 - 26 - dontUnpack = true; 27 - 28 - passthru = { 29 - tests = { inherit (nixosTests) minecraft-server; }; 30 - updateScript = ./update.sh; 31 - }; 32 - 33 - meta = with lib; { 34 - description = "Minecraft Server"; 35 - homepage = "https://minecraft.net"; 36 - license = licenses.unfreeRedistributable; 37 - platforms = platforms.unix; 38 - maintainers = with maintainers; [ thoughtpolice tomberek costrouc ]; 39 - }; 8 + packages = lib.mapAttrs' 9 + (version: value: { 10 + name = "minecraft-server_${escapeVersion version}"; 11 + value = callPackage ./derivation.nix { inherit (value) version url sha1; }; 12 + }) 13 + versions; 14 + in 15 + packages // { 16 + minecraft-server = builtins.getAttr "minecraft-server_${escapeVersion latestVersion}" packages; 40 17 }
+36
pkgs/games/minecraft-server/derivation.nix
··· 1 + { lib, stdenv, fetchurl, nixosTests, jre_headless, version, url, sha1 }: 2 + stdenv.mkDerivation { 3 + pname = "minecraft-server"; 4 + inherit version; 5 + 6 + src = fetchurl { inherit url sha1; }; 7 + 8 + preferLocalBuild = true; 9 + 10 + installPhase = '' 11 + mkdir -p $out/bin $out/lib/minecraft 12 + cp -v $src $out/lib/minecraft/server.jar 13 + 14 + cat > $out/bin/minecraft-server << EOF 15 + #!/bin/sh 16 + exec ${jre_headless}/bin/java \$@ -jar $out/lib/minecraft/server.jar nogui 17 + EOF 18 + 19 + chmod +x $out/bin/minecraft-server 20 + ''; 21 + 22 + dontUnpack = true; 23 + 24 + passthru = { 25 + tests = { inherit (nixosTests) minecraft-server; }; 26 + updateScript = ./update.py; 27 + }; 28 + 29 + meta = with lib; { 30 + description = "Minecraft Server"; 31 + homepage = "https://minecraft.net"; 32 + license = licenses.unfreeRedistributable; 33 + platforms = platforms.unix; 34 + maintainers = with maintainers; [ thoughtpolice tomberek costrouc ]; 35 + }; 36 + }
+147
pkgs/games/minecraft-server/update.py
··· 1 + #!/usr/bin/env nix-shell 2 + #!nix-shell -i python3 -p python3Packages.requests python3Packages.dataclasses-json 3 + 4 + import json 5 + from dataclasses import dataclass, field 6 + from datetime import datetime 7 + from typing import Any, Dict, List, Optional 8 + 9 + import requests 10 + from dataclasses_json import DataClassJsonMixin, LetterCase, config 11 + from marshmallow import fields 12 + 13 + 14 + @dataclass 15 + class Download(DataClassJsonMixin): 16 + sha1: str 17 + size: int 18 + url: str 19 + 20 + 21 + @dataclass 22 + class Version(DataClassJsonMixin): 23 + id: str 24 + type: str 25 + url: str 26 + time: datetime = field( 27 + metadata=config( 28 + encoder=datetime.isoformat, 29 + decoder=datetime.fromisoformat, 30 + mm_field=fields.DateTime(format="iso"), 31 + ) 32 + ) 33 + release_time: datetime = field( 34 + metadata=config( 35 + encoder=datetime.isoformat, 36 + decoder=datetime.fromisoformat, 37 + mm_field=fields.DateTime(format="iso"), 38 + letter_case=LetterCase.CAMEL, 39 + ) 40 + ) 41 + 42 + def get_manifest(self) -> Any: 43 + """Return the version's manifest.""" 44 + response = requests.get(self.url) 45 + response.raise_for_status() 46 + return response.json() 47 + 48 + def get_downloads(self) -> Dict[str, Download]: 49 + """ 50 + Return all downloadable files from the version's manifest, in Download 51 + objects. 52 + """ 53 + return { 54 + download_name: Download.from_dict(download_info) 55 + for download_name, download_info in self.get_manifest()["downloads"].items() 56 + } 57 + 58 + def get_server(self) -> Optional[Download]: 59 + """ 60 + If the version has a server download available, return the Download 61 + object for the server download. If the version does not have a server 62 + download avilable, return None. 63 + """ 64 + downloads = self.get_downloads() 65 + if "server" in downloads: 66 + return downloads["server"] 67 + return None 68 + 69 + 70 + def get_versions() -> List[Version]: 71 + """Return a list of Version objects for all available versions.""" 72 + response = requests.get( 73 + "https://launchermeta.mojang.com/mc/game/version_manifest.json" 74 + ) 75 + response.raise_for_status() 76 + data = response.json() 77 + return [Version.from_dict(version) for version in data["versions"]] 78 + 79 + 80 + def get_major_release(version_id: str) -> str: 81 + """ 82 + Return the major release for a version. The major release for 1.17 and 83 + 1.17.1 is 1.17. 84 + """ 85 + if not len(version_id.split(".")) >= 2: 86 + raise ValueError(f"version not in expected format: '{version_id}'") 87 + return ".".join(version_id.split(".")[:2]) 88 + 89 + 90 + def group_major_releases(releases: List[Version]) -> Dict[str, List[Version]]: 91 + """ 92 + Return a dictionary containing each version grouped by each major release. 93 + The key "1.17" contains a list with two Version objects, one for "1.17" 94 + and another for "1.17.1". 95 + """ 96 + groups: Dict[str, List[Version]] = {} 97 + for release in releases: 98 + major_release = get_major_release(release.id) 99 + if major_release not in groups: 100 + groups[major_release] = [] 101 + groups[major_release].append(release) 102 + return groups 103 + 104 + 105 + def get_latest_major_releases(releases: List[Version]) -> Dict[str, Version]: 106 + """ 107 + Return a dictionary containing the latest version for each major release. 108 + The latest major release for 1.16 is 1.16.5, so the key "1.16" contains a 109 + Version object for 1.16.5. 110 + """ 111 + return { 112 + major_release: sorted(releases, key=lambda x: x.id, reverse=True)[0] 113 + for major_release, releases in group_major_releases(releases).items() 114 + } 115 + 116 + 117 + def generate() -> Dict[str, Dict[str, str]]: 118 + """ 119 + Return a dictionary containing the latest url, sha1 and version for each major 120 + release. 121 + """ 122 + versions = get_versions() 123 + releases = list( 124 + filter(lambda version: version.type == "release", versions) 125 + ) # remove snapshots and betas 126 + latest_major_releases = get_latest_major_releases(releases) 127 + 128 + servers = { 129 + version: Download.schema().dump(download_info) # Download -> dict 130 + for version, download_info in { 131 + version: value.get_server() 132 + for version, value in latest_major_releases.items() 133 + }.items() 134 + if download_info is not None # versions < 1.2 do not have a server 135 + } 136 + for server in servers.values(): 137 + del server["size"] # don't need it 138 + 139 + for version, server in servers.items(): 140 + server["version"] = latest_major_releases[version].id 141 + return servers 142 + 143 + 144 + if __name__ == "__main__": 145 + with open("versions.json", "w") as file: 146 + json.dump(generate(), file, indent=2) 147 + file.write("\n")
-21
pkgs/games/minecraft-server/update.sh
··· 1 - #!/usr/bin/env nix-shell 2 - #!nix-shell -i bash -p curl jq common-updater-scripts 3 - 4 - BASEDIR="$(dirname "$0")" 5 - 6 - # get current release version 7 - versions=$(curl -s 'https://launchermeta.mojang.com/mc/game/version_manifest.json') 8 - version=$(echo $versions | jq .latest.release) 9 - url=$(echo $versions | jq -r ".versions[] | select(.id == $version) | .url") 10 - 11 - # get current server.jar 12 - versions=$(curl -s $url | jq .downloads.server) 13 - sha1=$(echo $versions | jq .sha1) 14 - url=$(echo $versions | jq .url) 15 - 16 - echo $version: $url:$sha1 17 - 18 - # change default.nix 19 - sed -i "s/version = \"[0-9.]*\";/version = ${version};/g" "$BASEDIR/default.nix" 20 - sed -i "s+url = \"[a-zA-Z0-9/:.]*/server.jar\";+url = $url;+g" "$BASEDIR/default.nix" 21 - sed -i "s/sha1 = \"[a-zA-Z0-9]*\";/sha1 = ${sha1};/g" "$BASEDIR/default.nix"
+87
pkgs/games/minecraft-server/versions.json
··· 1 + { 2 + "1.18": { 3 + "url": "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar", 4 + "sha1": "125e5adf40c659fd3bce3e66e67a16bb49ecc1b9", 5 + "version": "1.18.1" 6 + }, 7 + "1.17": { 8 + "url": "https://launcher.mojang.com/v1/objects/a16d67e5807f57fc4e550299cf20226194497dc2/server.jar", 9 + "sha1": "a16d67e5807f57fc4e550299cf20226194497dc2", 10 + "version": "1.17.1" 11 + }, 12 + "1.16": { 13 + "url": "https://launcher.mojang.com/v1/objects/1b557e7b033b583cd9f66746b7a9ab1ec1673ced/server.jar", 14 + "sha1": "1b557e7b033b583cd9f66746b7a9ab1ec1673ced", 15 + "version": "1.16.5" 16 + }, 17 + "1.15": { 18 + "url": "https://launcher.mojang.com/v1/objects/bb2b6b1aefcd70dfd1892149ac3a215f6c636b07/server.jar", 19 + "sha1": "bb2b6b1aefcd70dfd1892149ac3a215f6c636b07", 20 + "version": "1.15.2" 21 + }, 22 + "1.14": { 23 + "url": "https://launcher.mojang.com/v1/objects/3dc3d84a581f14691199cf6831b71ed1296a9fdf/server.jar", 24 + "sha1": "3dc3d84a581f14691199cf6831b71ed1296a9fdf", 25 + "version": "1.14.4" 26 + }, 27 + "1.13": { 28 + "url": "https://launcher.mojang.com/v1/objects/3737db93722a9e39eeada7c27e7aca28b144ffa7/server.jar", 29 + "sha1": "3737db93722a9e39eeada7c27e7aca28b144ffa7", 30 + "version": "1.13.2" 31 + }, 32 + "1.12": { 33 + "url": "https://launcher.mojang.com/v1/objects/886945bfb2b978778c3a0288fd7fab09d315b25f/server.jar", 34 + "sha1": "886945bfb2b978778c3a0288fd7fab09d315b25f", 35 + "version": "1.12.2" 36 + }, 37 + "1.11": { 38 + "url": "https://launcher.mojang.com/v1/objects/f00c294a1576e03fddcac777c3cf4c7d404c4ba4/server.jar", 39 + "sha1": "f00c294a1576e03fddcac777c3cf4c7d404c4ba4", 40 + "version": "1.11.2" 41 + }, 42 + "1.10": { 43 + "url": "https://launcher.mojang.com/v1/objects/3d501b23df53c548254f5e3f66492d178a48db63/server.jar", 44 + "sha1": "3d501b23df53c548254f5e3f66492d178a48db63", 45 + "version": "1.10.2" 46 + }, 47 + "1.9": { 48 + "url": "https://launcher.mojang.com/v1/objects/edbb7b1758af33d365bf835eb9d13de005b1e274/server.jar", 49 + "sha1": "edbb7b1758af33d365bf835eb9d13de005b1e274", 50 + "version": "1.9.4" 51 + }, 52 + "1.8": { 53 + "url": "https://launcher.mojang.com/v1/objects/b58b2ceb36e01bcd8dbf49c8fb66c55a9f0676cd/server.jar", 54 + "sha1": "b58b2ceb36e01bcd8dbf49c8fb66c55a9f0676cd", 55 + "version": "1.8.9" 56 + }, 57 + "1.7": { 58 + "url": "https://launcher.mojang.com/v1/objects/4cec86a928ec171fdc0c6b40de2de102f21601b5/server.jar", 59 + "sha1": "4cec86a928ec171fdc0c6b40de2de102f21601b5", 60 + "version": "1.7.9" 61 + }, 62 + "1.6": { 63 + "url": "https://launcher.mojang.com/v1/objects/050f93c1f3fe9e2052398f7bd6aca10c63d64a87/server.jar", 64 + "sha1": "050f93c1f3fe9e2052398f7bd6aca10c63d64a87", 65 + "version": "1.6.4" 66 + }, 67 + "1.5": { 68 + "url": "https://launcher.mojang.com/v1/objects/f9ae3f651319151ce99a0bfad6b34fa16eb6775f/server.jar", 69 + "sha1": "f9ae3f651319151ce99a0bfad6b34fa16eb6775f", 70 + "version": "1.5.2" 71 + }, 72 + "1.4": { 73 + "url": "https://launcher.mojang.com/v1/objects/2f0ec8efddd2f2c674c77be9ddb370b727dec676/server.jar", 74 + "sha1": "2f0ec8efddd2f2c674c77be9ddb370b727dec676", 75 + "version": "1.4.7" 76 + }, 77 + "1.3": { 78 + "url": "https://launcher.mojang.com/v1/objects/3de2ae6c488135596e073a9589842800c9f53bfe/server.jar", 79 + "sha1": "3de2ae6c488135596e073a9589842800c9f53bfe", 80 + "version": "1.3.2" 81 + }, 82 + "1.2": { 83 + "url": "https://launcher.mojang.com/v1/objects/d8321edc9470e56b8ad5c67bbd16beba25843336/server.jar", 84 + "sha1": "d8321edc9470e56b8ad5c67bbd16beba25843336", 85 + "version": "1.2.5" 86 + } 87 + }
+19 -1
pkgs/top-level/all-packages.nix
··· 30810 30810 30811 30811 minecraft = callPackage ../games/minecraft { }; 30812 30812 30813 - minecraft-server = callPackage ../games/minecraft-server { }; 30813 + inherit (import ../games/minecraft-server { inherit callPackage lib; }) 30814 + minecraft-server_1_2 30815 + minecraft-server_1_3 30816 + minecraft-server_1_4 30817 + minecraft-server_1_5 30818 + minecraft-server_1_6 30819 + minecraft-server_1_7 30820 + minecraft-server_1_8 30821 + minecraft-server_1_9 30822 + minecraft-server_1_10 30823 + minecraft-server_1_11 30824 + minecraft-server_1_12 30825 + minecraft-server_1_13 30826 + minecraft-server_1_14 30827 + minecraft-server_1_15 30828 + minecraft-server_1_16 30829 + minecraft-server_1_17 30830 + minecraft-server_1_18 30831 + minecraft-server; 30814 30832 30815 30833 moon-buggy = callPackage ../games/moon-buggy {}; 30816 30834