Add plugin helper with agent skill for updating plugins
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import tomllib
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
VALID_STRATEGIES = {"dll-to-plugins", "zip-to-pending", "bsipa-zip", "root-zip", "manual"}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Dependency:
|
||||
id: str
|
||||
constraint: str | None = None
|
||||
required: bool = True
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RegistryPlugin:
|
||||
id: str
|
||||
name: str
|
||||
repo: str | None
|
||||
asset_patterns: tuple[str, ...] = ()
|
||||
install_strategy: str = "manual"
|
||||
category: str | None = None
|
||||
dependencies: tuple[Dependency, ...] = ()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Registry:
|
||||
plugins: dict[str, RegistryPlugin] = field(default_factory=dict)
|
||||
|
||||
def get(self, plugin_id: str) -> RegistryPlugin | None:
|
||||
return self.plugins.get(plugin_id)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LockedPlugin:
|
||||
id: str
|
||||
repo: str | None
|
||||
tag: str | None
|
||||
asset: str | None
|
||||
sha256: str | None
|
||||
install_strategy: str | None = None
|
||||
reason: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Lockfile:
|
||||
beat_saber_version: str
|
||||
instance: str
|
||||
plugins: tuple[LockedPlugin, ...]
|
||||
|
||||
|
||||
def _load_toml(path: Path) -> dict[str, Any]:
|
||||
with path.open("rb") as handle:
|
||||
return tomllib.load(handle)
|
||||
|
||||
|
||||
def load_registry(path: Path) -> Registry:
|
||||
if not path.exists():
|
||||
return Registry()
|
||||
data = _load_toml(path)
|
||||
plugins: dict[str, RegistryPlugin] = {}
|
||||
for item in data.get("plugins", []):
|
||||
dependencies = tuple(
|
||||
Dependency(
|
||||
id=dep["id"],
|
||||
constraint=dep.get("constraint"),
|
||||
required=dep.get("required", True),
|
||||
)
|
||||
for dep in item.get("dependencies", [])
|
||||
)
|
||||
strategy = item.get("install_strategy", "manual")
|
||||
if strategy not in VALID_STRATEGIES:
|
||||
raise ValueError(f"{path}: invalid install_strategy for {item['id']}: {strategy}")
|
||||
plugin = RegistryPlugin(
|
||||
id=item["id"],
|
||||
name=item.get("name", item["id"]),
|
||||
repo=item.get("repo"),
|
||||
asset_patterns=tuple(item.get("asset_patterns", [])),
|
||||
install_strategy=strategy,
|
||||
category=item.get("category"),
|
||||
dependencies=dependencies,
|
||||
)
|
||||
plugins[plugin.id] = plugin
|
||||
return Registry(plugins)
|
||||
|
||||
|
||||
def load_lockfile(path: Path) -> Lockfile:
|
||||
data = _load_toml(path)
|
||||
plugins = tuple(
|
||||
LockedPlugin(
|
||||
id=item["id"],
|
||||
repo=item.get("repo"),
|
||||
tag=item.get("tag"),
|
||||
asset=item.get("asset"),
|
||||
sha256=item.get("sha256"),
|
||||
install_strategy=item.get("install_strategy"),
|
||||
reason=item.get("reason"),
|
||||
)
|
||||
for item in data.get("plugins", [])
|
||||
)
|
||||
return Lockfile(
|
||||
beat_saber_version=data["beat_saber_version"],
|
||||
instance=data.get("instance", data["beat_saber_version"]),
|
||||
plugins=plugins,
|
||||
)
|
||||
Reference in New Issue
Block a user