Refactor plugin registry into separate files per plugin
This commit is contained in:
+137
-1
@@ -22,7 +22,7 @@ from plugin_helper.config import is_windows, load_local_config, resolve_runtime_
|
||||
from plugin_helper.fsutil import sha256_file
|
||||
from plugin_helper.installer import apply_plan, disable_plugin, uninstall_plugin
|
||||
from plugin_helper.instances import get_instance, list_instances
|
||||
from plugin_helper.models import Lockfile, LockedPlugin, Registry, RegistryPlugin
|
||||
from plugin_helper.models import Dependency, Lockfile, LockedPlugin, Registry, RegistryPlugin, load_registry
|
||||
from plugin_helper.operations import enable_disabled_plugin
|
||||
from plugin_helper.planner import create_plan
|
||||
from plugin_helper.scanner import scan_bootstrap_files, scan_instance
|
||||
@@ -40,6 +40,35 @@ from plugin_helper.userdata import (
|
||||
|
||||
|
||||
class PluginHelperTests(unittest.TestCase):
|
||||
def test_load_registry_reads_plugin_directory(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
registry_dir = root / "registry" / "plugins"
|
||||
registry_dir.mkdir(parents=True)
|
||||
(registry_dir / "example.toml").write_text(
|
||||
"""
|
||||
id = "example"
|
||||
name = "Example"
|
||||
repo = "owner/example"
|
||||
asset_patterns = ["Example-*.zip"]
|
||||
install_strategy = "bsipa-zip"
|
||||
category = "ui"
|
||||
dependencies = [
|
||||
{ id = "bsipa", constraint = ">=4.3.7" },
|
||||
]
|
||||
""".lstrip(),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
registry = load_registry(registry_dir)
|
||||
|
||||
plugin = registry.get("example")
|
||||
self.assertIsNotNone(plugin)
|
||||
assert plugin is not None
|
||||
self.assertEqual(plugin.name, "Example")
|
||||
self.assertEqual(plugin.asset_patterns, ("Example-*.zip",))
|
||||
self.assertEqual(plugin.dependencies, (Dependency(id="bsipa", constraint=">=4.3.7"),))
|
||||
|
||||
def test_normalize_beatmods_current_nested_response(self) -> None:
|
||||
payload = {
|
||||
"mods": [
|
||||
@@ -872,6 +901,113 @@ sha256 = "{sha256_file(asset)}"
|
||||
|
||||
self.assertEqual(plan["changes"][0]["source"], str(asset))
|
||||
|
||||
def test_plan_expands_required_dependencies_for_selected_plugin(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
work = Path(tmp)
|
||||
instance = work / "instances" / "1.40.8"
|
||||
state = work / "state"
|
||||
instance.mkdir(parents=True)
|
||||
(instance / "Beat Saber_Data").mkdir()
|
||||
plugin_asset = plugin_downloads_dir(state, "1.40.8", "example") / "Example.dll"
|
||||
dependency_asset = plugin_downloads_dir(state, "1.40.8", "dependency") / "Dependency.dll"
|
||||
plugin_asset.write_bytes(b"managed dll")
|
||||
dependency_asset.write_bytes(b"dependency dll")
|
||||
|
||||
plan, _ = create_plan(
|
||||
instance="1.40.8",
|
||||
instance_path=instance,
|
||||
beat_saber_version="1.40.8",
|
||||
registry=Registry(
|
||||
{
|
||||
"example": RegistryPlugin(
|
||||
id="example",
|
||||
name="Example",
|
||||
repo=None,
|
||||
install_strategy="dll-to-plugins",
|
||||
dependencies=(Dependency(id="dependency"),),
|
||||
),
|
||||
"dependency": RegistryPlugin(
|
||||
id="dependency",
|
||||
name="Dependency",
|
||||
repo=None,
|
||||
install_strategy="dll-to-plugins",
|
||||
),
|
||||
}
|
||||
),
|
||||
lockfile=Lockfile(
|
||||
beat_saber_version="1.40.8",
|
||||
instance="1.40.8",
|
||||
plugins=(
|
||||
LockedPlugin(
|
||||
id="example",
|
||||
repo=None,
|
||||
tag=None,
|
||||
asset="Example.dll",
|
||||
sha256=sha256_file(plugin_asset),
|
||||
),
|
||||
LockedPlugin(
|
||||
id="dependency",
|
||||
repo=None,
|
||||
tag=None,
|
||||
asset="Dependency.dll",
|
||||
sha256=sha256_file(dependency_asset),
|
||||
),
|
||||
),
|
||||
),
|
||||
state_root=state,
|
||||
repo_root=work,
|
||||
selected={"example"},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
{change["plugin"] for change in plan["changes"]},
|
||||
{"example", "dependency"},
|
||||
)
|
||||
|
||||
def test_plan_rejects_selected_plugin_with_unlocked_required_dependency(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
work = Path(tmp)
|
||||
instance = work / "instances" / "1.40.8"
|
||||
state = work / "state"
|
||||
instance.mkdir(parents=True)
|
||||
(instance / "Beat Saber_Data").mkdir()
|
||||
asset = plugin_downloads_dir(state, "1.40.8", "example") / "Example.dll"
|
||||
asset.write_bytes(b"managed dll")
|
||||
|
||||
with self.assertRaisesRegex(ValueError, "required dependency is not locked"):
|
||||
create_plan(
|
||||
instance="1.40.8",
|
||||
instance_path=instance,
|
||||
beat_saber_version="1.40.8",
|
||||
registry=Registry(
|
||||
{
|
||||
"example": RegistryPlugin(
|
||||
id="example",
|
||||
name="Example",
|
||||
repo=None,
|
||||
install_strategy="dll-to-plugins",
|
||||
dependencies=(Dependency(id="missing"),),
|
||||
),
|
||||
}
|
||||
),
|
||||
lockfile=Lockfile(
|
||||
beat_saber_version="1.40.8",
|
||||
instance="1.40.8",
|
||||
plugins=(
|
||||
LockedPlugin(
|
||||
id="example",
|
||||
repo=None,
|
||||
tag=None,
|
||||
asset="Example.dll",
|
||||
sha256=sha256_file(asset),
|
||||
),
|
||||
),
|
||||
),
|
||||
state_root=state,
|
||||
repo_root=work,
|
||||
selected={"example"},
|
||||
)
|
||||
|
||||
def test_zip_member_cannot_escape_instance(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
work = Path(tmp)
|
||||
|
||||
Reference in New Issue
Block a user