diff --git a/generateQuilt.py b/generateQuilt.py index ad0e0db..377982f 100755 --- a/generateQuilt.py +++ b/generateQuilt.py @@ -1,111 +1,111 @@ -from fabricutil import * +import json +import os -PMC_DIR = os.environ["PMC_DIR"] -UPSTREAM_DIR = os.environ["UPSTREAM_DIR"] +from meta.common import ensure_component_dir, polymc_path, upstream_path, transform_maven_key +from meta.common.quilt import JARS_DIR, INSTALLER_INFO_DIR, META_DIR, INTERMEDIARY_COMPONENT, LOADER_COMPONENT, \ + USE_QUILT_MAPPINGS +from meta.model import MetaVersion, Dependency, Library, MetaPackage, GradleSpecifier +from meta.model.fabric import FabricJarInfo, FabricInstallerDataV1, FabricMainClasses -# TODO: Switch to Quilt Mappings once the time has come -USE_QUILT_MAPPINGS = False +PMC_DIR = polymc_path() +UPSTREAM_DIR = upstream_path() -# turn loader versions into packages -loaderRecommended = [] -loaderVersions = [] -intermediaryRecommended = [] -intermediaryVersions = [] +ensure_component_dir(LOADER_COMPONENT) +ensure_component_dir(INTERMEDIARY_COMPONENT) -def mkdirs(path): - if not os.path.exists(path): - os.makedirs(path) +def load_jar_info(artifact_key) -> FabricJarInfo: + return FabricJarInfo.parse_file(os.path.join(UPSTREAM_DIR, JARS_DIR, f"{artifact_key}.json")) -mkdirs(PMC_DIR + "/org.quiltmc.quilt-loader") -mkdirs(PMC_DIR + "/org.quiltmc.quilt-mappings") +def load_installer_info(version) -> FabricInstallerDataV1: + return FabricInstallerDataV1.parse_file(os.path.join(UPSTREAM_DIR, INSTALLER_INFO_DIR, f"{version}.json")) -def loadJarInfo(mavenKey): - with open(UPSTREAM_DIR + "/quilt/jars/" + mavenKey.replace(":", ".") + ".json", 'r', - encoding='utf-8') as jarInfoFile: - return FabricJarInfo(json.load(jarInfoFile)) +def process_loader_version(entry) -> MetaVersion: + jar_info = load_jar_info(transform_maven_key(entry["maven"])) + installer_info = load_installer_info(entry["version"]) + + v = MetaVersion(name="Quilt Loader", uid=LOADER_COMPONENT, version=entry["version"]) + v.release_time = jar_info.release_time + v.requires = [Dependency(uid=INTERMEDIARY_COMPONENT)] + v.order = 10 + v.type = "release" + if isinstance(installer_info.main_class, FabricMainClasses): + v.main_class = installer_info.main_class.client + else: + v.main_class = installer_info.main_class + v.libraries = [] + v.libraries.extend(installer_info.libraries.common) + v.libraries.extend(installer_info.libraries.client) + loader_lib = Library(name=GradleSpecifier.from_string(entry["maven"]), + url="https://maven.quiltmc.org/repository/release") + v.libraries.append(loader_lib) + return v -def processLoaderVersion(loaderVersion, it, loaderData): - if (len(loaderRecommended) < 1): # TODO figure out actual stable version - loaderRecommended.append(loaderVersion) - versionJarInfo = loadJarInfo(it["maven"]) - version = PolyMCVersionFile(name="Quilt Loader", uid="org.quiltmc.quilt-loader", version=loaderVersion) - version.releaseTime = versionJarInfo.releaseTime +def process_intermediary_version(entry) -> MetaVersion: + minecraft_version = entry["version"].split("+", 2)[0] # version format is like 1.18.2-pre1+build.1 + + jar_info = load_jar_info(transform_maven_key(entry["maven"])) + + v = MetaVersion(name="Quilt Intermediary Mappings", uid=INTERMEDIARY_COMPONENT, version=entry["version"]) + v.release_time = jar_info.release_time + v.requires = [Dependency(uid='net.minecraft', equals=minecraft_version)] + v.order = 11 + v.type = "release" + v.libraries = [] + v.volatile = True + intermediary_lib = Library(name=GradleSpecifier.from_string(entry["maven"]), + url="https://maven.quiltmc.org/repository/release") + v.libraries.append(intermediary_lib) + return v + + +def main(): + recommended_loader_versions = [] + recommended_intermediary_versions = [] + + with open(os.path.join(UPSTREAM_DIR, META_DIR, "loader.json"), 'r', encoding='utf-8') as f: + loader_version_index = json.load(f) + for entry in loader_version_index: + version = entry["version"] + print(f"Processing loader {version}") + + v = process_loader_version(entry) + + if not recommended_loader_versions: # first (newest) loader is recommended + recommended_loader_versions.append(version) + + v.write(os.path.join(PMC_DIR, LOADER_COMPONENT, f"{v.version}.json")) + if USE_QUILT_MAPPINGS: - version.requires = [DependencyEntry(uid='org.quiltmc.quilt-mappings')] - else: - version.requires = [DependencyEntry(uid='net.fabricmc.intermediary')] - version.order = 10 - version.type = "release" - if isinstance(loaderData.mainClass, dict): - version.mainClass = loaderData.mainClass["client"] - else: - version.mainClass = loaderData.mainClass - version.libraries = [] - version.libraries.extend(loaderData.libraries.common) - version.libraries.extend(loaderData.libraries.client) - loaderLib = PolyMCLibrary(name=GradleSpecifier(it["maven"]), url="https://maven.quiltmc.org/repository/release") - version.libraries.append(loaderLib) - loaderVersions.append(version) + with open(os.path.join(UPSTREAM_DIR, META_DIR, "quilt-mappings.json"), 'r', encoding='utf-8') as f: + intermediary_version_index = json.load(f) + for entry in intermediary_version_index: + version = entry["version"] + print(f"Processing intermediary {version}") + + v = process_intermediary_version(entry) + + recommended_intermediary_versions.append(version) # all intermediaries are recommended + + v.write(os.path.join(PMC_DIR, INTERMEDIARY_COMPONENT, f"{v.version}.json")) + + package = MetaPackage(uid=LOADER_COMPONENT, name='Quilt Loader') + package.recommended = recommended_loader_versions + package.description = "The Quilt project is an open, community-driven modding toolchain designed primarily for Minecraft." + package.project_url = "https://quiltmc.org/" + package.authors = ["Quilt Project"] + package.write(os.path.join(PMC_DIR, LOADER_COMPONENT, "package.json")) + + package = MetaPackage(uid=INTERMEDIARY_COMPONENT, name='Quilt Intermediary Mappings') + package.recommended = recommended_intermediary_versions + package.description = "Intermediary mappings allow using Quilt Loader with mods for Minecraft in a more compatible manner." + package.project_url = "https://quiltmc.org/" + package.authors = ["Quilt Project"] + package.write(os.path.join(PMC_DIR, INTERMEDIARY_COMPONENT, "package.json")) -def processIntermediaryVersion(it): - minecraftVersion = it["version"].split("+", 2)[0] # version format is like 1.18.2-pre1+build.1 - - intermediaryRecommended.append(it["version"]) - versionJarInfo = loadJarInfo(it["maven"]) - version = PolyMCVersionFile(name="Quilt Intermediary Mappings", uid="org.quiltmc.quilt-mappings", version=it["version"]) - version.releaseTime = versionJarInfo.releaseTime - version.requires = [DependencyEntry(uid='net.minecraft', equals=minecraftVersion)] - version.order = 11 - version.type = "release" - version.libraries = [] - version.volatile = True - mappingLib = PolyMCLibrary(name=GradleSpecifier(it["maven"]), url="https://maven.quiltmc.org/repository/release") - version.libraries.append(mappingLib) - intermediaryVersions.append(version) - - -with open(UPSTREAM_DIR + "/quilt/meta-v3/loader.json", 'r', encoding='utf-8') as loaderVersionIndexFile: - loaderVersionIndex = json.load(loaderVersionIndexFile) - for it in loaderVersionIndex: - version = it["version"] - with open(UPSTREAM_DIR + "/quilt/loader-installer-json/" + version + ".json", 'r', - encoding='utf-8') as loaderVersionFile: - ldata = json.load(loaderVersionFile) - ldata = FabricInstallerDataV1(ldata) - processLoaderVersion(version, it, ldata) - -if USE_QUILT_MAPPINGS: - with open(UPSTREAM_DIR + "/quilt/meta-v3/quilt-mappings.json", 'r', encoding='utf-8') as intermediaryVersionIndexFile: - intermediaryVersionIndex = json.load(intermediaryVersionIndexFile) - for it in intermediaryVersionIndex: - processIntermediaryVersion(it) - -for version in loaderVersions: - outFilepath = PMC_DIR + "/org.quiltmc.quilt-loader/%s.json" % version.version - with open(outFilepath, 'w') as outfile: - json.dump(version.to_json(), outfile, sort_keys=True, indent=4) - -sharedData = PolyMCSharedPackageData(uid='org.quiltmc.quilt-loader', name='Quilt Loader') -sharedData.recommended = loaderRecommended -sharedData.description = "The Quilt project is an open, community-driven modding toolchain designed primarily for Minecraft." -sharedData.projectUrl = "https://quiltmc.org" -sharedData.authors = ["Quilt Project"] -sharedData.write() - -if USE_QUILT_MAPPINGS: - for version in intermediaryVersions: - outFilepath = PMC_DIR + "/org.quiltmc.quilt-mappings/%s.json" % version.version - with open(outFilepath, 'w') as outfile: - json.dump(version.to_json(), outfile, sort_keys=True, indent=4) - - sharedData = PolyMCSharedPackageData(uid='org.quiltmc.quilt-mappings', name='Quilt Intermediary Mappings') - sharedData.recommended = intermediaryRecommended - sharedData.description = "Intermediary mappings allow using Quilt Loader with mods for Minecraft in a more compatible manner." - sharedData.projectUrl = "https://quiltmc.org" - sharedData.authors = ["Quilt Project"] - sharedData.write() +if __name__ == '__main__': + main() diff --git a/meta/common/quilt.py b/meta/common/quilt.py new file mode 100644 index 0000000..6cf4fe0 --- /dev/null +++ b/meta/common/quilt.py @@ -0,0 +1,17 @@ +from os.path import join +from .fabric import INTERMEDIARY_COMPONENT as FABRIC_INTERMEDIARY_COMPONENT + +# Right now Quilt recommends using Fabric's intermediary +USE_QUILT_MAPPINGS = False + +BASE_DIR = "quilt" + +JARS_DIR = join(BASE_DIR, "jars") +INSTALLER_INFO_DIR = join(BASE_DIR, "loader-installer-json") +META_DIR = join(BASE_DIR, "meta-v3") + +LOADER_COMPONENT = "org.quiltmc.quilt-loader" +INTERMEDIARY_COMPONENT = "org.quiltmc.quilt-mappings" + +if not USE_QUILT_MAPPINGS: + INTERMEDIARY_COMPONENT = FABRIC_INTERMEDIARY_COMPONENT diff --git a/updateQuilt.py b/updateQuilt.py index c4f76a9..c8594fb 100755 --- a/updateQuilt.py +++ b/updateQuilt.py @@ -1,37 +1,41 @@ import hashlib +import json +import os import zipfile +from datetime import datetime import requests from cachecontrol import CacheControl from cachecontrol.caches import FileCache -from fabricutil import * -DATETIME_FORMAT_HTTP = "%a, %d %b %Y %H:%M:%S %Z" +from meta.common import upstream_path, ensure_upstream_dir, transform_maven_key +from meta.common.quilt import JARS_DIR, INSTALLER_INFO_DIR, META_DIR +from meta.common.fabric import DATETIME_FORMAT_HTTP +from meta.model.fabric import FabricJarInfo -UPSTREAM_DIR = os.environ["UPSTREAM_DIR"] +UPSTREAM_DIR = upstream_path() + +ensure_upstream_dir(JARS_DIR) +ensure_upstream_dir(INSTALLER_INFO_DIR) +ensure_upstream_dir(META_DIR) forever_cache = FileCache('caches/http_cache', forever=True) sess = CacheControl(requests.Session(), forever_cache) -def mkdirs(path): - if not os.path.exists(path): - os.makedirs(path) - - def filehash(filename, hashtype, blocksize=65536): - hash = hashtype() + h = hashtype() with open(filename, "rb") as f: for block in iter(lambda: f.read(blocksize), b""): - hash.update(block) - return hash.hexdigest() + h.update(block) + return h.hexdigest() -def get_maven_url(mavenKey, server, ext): - mavenParts = mavenKey.split(":", 3) - mavenVerUrl = server + mavenParts[0].replace(".", "/") + "/" + mavenParts[1] + "/" + mavenParts[2] + "/" - mavenUrl = mavenVerUrl + mavenParts[1] + "-" + mavenParts[2] + ext - return mavenUrl +def get_maven_url(maven_key, server, ext): + parts = maven_key.split(":", 3) + maven_ver_url = server + parts[0].replace(".", "/") + "/" + parts[1] + "/" + parts[2] + "/" + maven_url = maven_ver_url + parts[1] + "-" + parts[2] + ext + return maven_url def get_json_file(path, url): @@ -56,12 +60,11 @@ def head_file(url): def get_binary_file(path, url): - with open(path, 'w', encoding='utf-8') as f: + with open(path, 'wb') as f: r = sess.get(url) r.raise_for_status() - with open(path, 'wb') as f: - for chunk in r.iter_content(chunk_size=128): - f.write(chunk) + for chunk in r.iter_content(chunk_size=128): + f.write(chunk) def compute_jar_file(path, url): @@ -70,7 +73,7 @@ def compute_jar_file(path, url): try: # Let's not download a Jar file if we don't need to. headers = head_file(url) - tstamp = datetime.datetime.strptime(headers["Last-Modified"], DATETIME_FORMAT_HTTP) + tstamp = datetime.strptime(headers["Last-Modified"], DATETIME_FORMAT_HTTP) sha1 = get_plaintext(url + ".sha1") sha256 = get_plaintext(url + ".sha256") size = int(headers["Content-Length"]) @@ -80,11 +83,11 @@ def compute_jar_file(path, url): jar_path = path + ".jar" get_binary_file(jar_path, url) - tstamp = datetime.datetime.fromtimestamp(0) - with zipfile.ZipFile(jar_path, 'r') as jar: + tstamp = datetime.fromtimestamp(0) + with zipfile.ZipFile(jar_path) as jar: allinfo = jar.infolist() for info in allinfo: - tstamp_new = datetime.datetime(*info.date_time) + tstamp_new = datetime(*info.date_time) if tstamp_new > tstamp: tstamp = tstamp_new @@ -92,30 +95,28 @@ def compute_jar_file(path, url): sha256 = filehash(jar_path, hashlib.sha256) size = os.path.getsize(jar_path) - data = FabricJarInfo() - data.releaseTime = tstamp - data.sha1 = sha1 - data.sha256 = sha256 - data.size = size - with open(path + ".json", 'w') as outfile: - json.dump(data.to_json(), outfile, sort_keys=True, indent=4) + data = FabricJarInfo(release_time=tstamp, sha1=sha1, sha256=sha256, size=size) + data.write(path + ".json") -mkdirs(UPSTREAM_DIR + "/quilt/meta-v3") -mkdirs(UPSTREAM_DIR + "/quilt/loader-installer-json") -mkdirs(UPSTREAM_DIR + "/quilt/jars") +def main(): + # get the version list for each component we are interested in + for component in ["quilt-mappings", "loader"]: + index = get_json_file(os.path.join(UPSTREAM_DIR, META_DIR, f"{component}.json"), + "https://meta.quiltmc.org/v3/versions/" + component) + for it in index: + print(f"Processing {component} {it['version']} ") + jar_maven_url = get_maven_url(it["maven"], "https://maven.quiltmc.org/repository/release/", ".jar") + compute_jar_file(os.path.join(UPSTREAM_DIR, JARS_DIR, transform_maven_key(it["maven"])), jar_maven_url) -# get the version list for each component we are interested in -for component in ["quilt-mappings", "loader"]: - index = get_json_file(UPSTREAM_DIR + "/quilt/meta-v3/" + component + ".json", - "https://meta.quiltmc.org/v3/versions/" + component) - for it in index: - jarMavenUrl = get_maven_url(it["maven"], "https://maven.quiltmc.org/repository/release/", ".jar") - compute_jar_file(UPSTREAM_DIR + "/quilt/jars/" + it["maven"].replace(":", "."), jarMavenUrl) + # for each loader, download installer JSON file from maven + with open(os.path.join(UPSTREAM_DIR, META_DIR, "loader.json"), 'r', encoding='utf-8') as loaderVersionIndexFile: + loader_version_index = json.load(loaderVersionIndexFile) + for it in loader_version_index: + print(f"Downloading installer info for loader {it['version']} ") + maven_url = get_maven_url(it["maven"], "https://maven.quiltmc.org/repository/release/", ".json") + get_json_file(os.path.join(UPSTREAM_DIR, INSTALLER_INFO_DIR, f"{it['version']}.json"), maven_url) -# for each loader, download installer JSON file from maven -with open(UPSTREAM_DIR + "/quilt/meta-v3/loader.json", 'r', encoding='utf-8') as loaderVersionIndexFile: - loaderVersionIndex = json.load(loaderVersionIndexFile) - for it in loaderVersionIndex: - mavenUrl = get_maven_url(it["maven"], "https://maven.quiltmc.org/repository/release/", ".json") - get_json_file(UPSTREAM_DIR + "/quilt/loader-installer-json/" + it["version"] + ".json", mavenUrl) + +if __name__ == '__main__': + main()