modpack/scripts/list_orphans.py
2024-01-30 20:02:32 -05:00

99 lines
3.3 KiB
Python

import argparse
import sys
import logging
import requests
import json
import tomllib
from typing import List, Tuple, Dict, Union
from pathlib import Path
logger = logging.getLogger(__name__)
def main() -> int:
# Handle program arguments
ap = argparse.ArgumentParser()
ap.add_argument("--dot", help="Output a graphviz dot file here", type=Path)
ap.add_argument(
"-v", "--verbose", help="Enable verbose logging", action="store_true"
)
args = ap.parse_args()
# Configure logging
logging.basicConfig(
level=logging.DEBUG if args.verbose else logging.INFO,
format="%(levelname)s: %(message)s",
)
# Get a list of all toml files in the mods dir
mods_tomls = list((Path(__file__).parent.parent / "mods").glob("*.toml"))
# Look for update.modrinth.mod-id and update.modrinth.version
mods = []
for mod_toml in mods_tomls:
with open(mod_toml, "rb") as f:
mod = tomllib.load(f)
if "update" in mod and "modrinth" in mod["update"]:
mods.append(
{
"name": mod["name"],
"mod_id": mod["update"]["modrinth"]["mod-id"],
"version_id": mod["update"]["modrinth"]["version"],
"dependencies": [],
}
)
# Build a map of dependencies
# mod_dependencies: Dict[str, List[str]] = {}
for mod in mods:
# Read the version metadata
version_metadata = requests.get(
f"https://api.modrinth.com/v2/version/{mod['version_id']}"
).json()
# Track the dependencies
for dependency in version_metadata.get("dependencies", {}):
if "project_id" in dependency:
mod["dependencies"].append(
{"name": None, "mod_id": dependency["project_id"]}
)
# In-fill all the dependency names (that we know about)
for mod in mods:
for dependency in mod["dependencies"]:
for mod_data in mods:
if mod_data["mod_id"] == dependency["mod_id"]:
dependency["name"] = mod_data["name"]
break
# De-dupe dependencies
for mod in mods:
mod["dependencies"] = list({v['name']:v for v in mod["dependencies"]}.values())
# If graphviz output requested, write it
if args.dot:
with open(args.dot, "w") as f:
f.write("digraph {\n")
for mod in mods:
f.write(f'"{mod["name"]}" [label="{mod["name"]}"];\n')
for dependency in mod["dependencies"]:
f.write(f'"{mod["name"]}" -> "{dependency["name"]}";\n')
f.write("}\n")
# Build a map of all mods, and which other mods depend upon them
mod_to_dependers: Dict[str, List[str]] = {name:[] for name in [mod["name"] for mod in mods]}
for mod in mods:
for dependency in mod["dependencies"]:
if dependency["name"] not in mod_to_dependers:
mod_to_dependers[dependency["name"]] = []
mod_to_dependers[dependency["name"]].append(mod["name"])
print(json.dumps(mod_to_dependers, indent=4))
return 0
if __name__ == "__main__":
sys.exit(main())