mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 03:15:56 +00:00
perf(web-app-nextcloud): plan the plugin pipeline from one app:list
Every addon ran through the install, enable and configure stages on its own, and each stage asked occ for the plugin's state again. The role now reads occ app:list --output=json once, and the new nextcloud_plugin_plan filter replays the addon order (an enabled entry switches its incompatible_plugins off and itself on, a disabled entry switches itself off, the later entry wins) and splits the app ids into disable, install, enable and configure. One app:disable call takes every id that has to go off; the install, enable and configure includes loop only over the ids that need that stage, so an already enabled plugin skips straight to its configuration. A plugin shipped as a pinned archive still goes through install on every run. On echoserver the plugin phase took 608 s in full-9 for 51 addons; a repeat deploy is derived at about 195 s instead of about 550 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
d670d4f537
commit
3044ae7a2e
5 files changed
+276
-23
No files matched your search
+146
@@ -0,0 +1,146 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from . import PROJECT_ROOT
|
||||
|
||||
|
||||
def _load_module(rel_path: str, name: str):
|
||||
path = PROJECT_ROOT / rel_path
|
||||
spec = importlib.util.spec_from_file_location(name, str(path))
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
sys.modules[name] = mod
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
plan_mod = _load_module(
|
||||
"roles/web-app-nextcloud/filter_plugins/nextcloud_plugin_plan.py",
|
||||
"nextcloud_plugin_plan",
|
||||
)
|
||||
nextcloud_plugin_plan = plan_mod.nextcloud_plugin_plan
|
||||
|
||||
|
||||
def _items(*entries):
|
||||
return [{"key": key, "value": value} for key, value in entries]
|
||||
|
||||
|
||||
def _apps(enabled=(), disabled=()):
|
||||
return {
|
||||
"enabled": dict.fromkeys(enabled, "1.0.0"),
|
||||
"disabled": dict.fromkeys(disabled, "1.0.0"),
|
||||
}
|
||||
|
||||
|
||||
class TestNextcloudPluginPlan(unittest.TestCase):
|
||||
def test_enabled_and_running_plugins_only_get_configured(self):
|
||||
plan = nextcloud_plugin_plan(
|
||||
_items(("calendar", {"enabled": True}), ("deck", {"enabled": True})),
|
||||
_apps(enabled=("calendar", "deck")),
|
||||
)
|
||||
self.assertEqual(
|
||||
plan,
|
||||
{
|
||||
"disable": [],
|
||||
"install": [],
|
||||
"enable": [],
|
||||
"configure": ["calendar", "deck"],
|
||||
},
|
||||
)
|
||||
|
||||
def test_missing_plugin_is_installed(self):
|
||||
plan = nextcloud_plugin_plan(_items(("deck", {"enabled": True})), _apps())
|
||||
self.assertEqual(plan["install"], ["deck"])
|
||||
self.assertEqual(plan["configure"], [])
|
||||
|
||||
def test_installed_but_disabled_plugin_is_enabled(self):
|
||||
plan = nextcloud_plugin_plan(
|
||||
_items(("recognize", {"enabled": True})), _apps(disabled=("recognize",))
|
||||
)
|
||||
self.assertEqual(plan["enable"], ["recognize"])
|
||||
self.assertEqual(plan["install"], [])
|
||||
|
||||
def test_pinned_archive_always_goes_through_install(self):
|
||||
plan = nextcloud_plugin_plan(
|
||||
_items(
|
||||
(
|
||||
"onlyoffice",
|
||||
{"enabled": True, "config": {"archive": "https://x/o.tar.gz"}},
|
||||
)
|
||||
),
|
||||
_apps(enabled=("onlyoffice",)),
|
||||
)
|
||||
self.assertEqual(plan["install"], ["onlyoffice"])
|
||||
self.assertEqual(plan["configure"], [])
|
||||
|
||||
def test_disabled_plugin_is_disabled_only_while_it_runs(self):
|
||||
running = nextcloud_plugin_plan(
|
||||
_items(("news", {"enabled": False})), _apps(enabled=("news",))
|
||||
)
|
||||
idle = nextcloud_plugin_plan(
|
||||
_items(("news", {"enabled": False})), _apps(disabled=("news",))
|
||||
)
|
||||
self.assertEqual(running["disable"], ["news"])
|
||||
self.assertEqual(idle["disable"], [])
|
||||
|
||||
def test_later_entry_wins_like_the_per_plugin_loop(self):
|
||||
items = _items(
|
||||
("fileslibreofficeedit", {"enabled": True}),
|
||||
(
|
||||
"onlyoffice",
|
||||
{
|
||||
"enabled": True,
|
||||
"config": {
|
||||
"incompatible_plugins": [
|
||||
"richdocuments",
|
||||
"fileslibreofficeedit",
|
||||
]
|
||||
},
|
||||
},
|
||||
),
|
||||
("richdocuments", {"enabled": True}),
|
||||
)
|
||||
plan = nextcloud_plugin_plan(
|
||||
items,
|
||||
_apps(enabled=("fileslibreofficeedit", "onlyoffice", "richdocuments")),
|
||||
)
|
||||
self.assertEqual(plan["disable"], ["fileslibreofficeedit"])
|
||||
self.assertEqual(plan["configure"], ["onlyoffice", "richdocuments"])
|
||||
self.assertEqual(plan["install"], [])
|
||||
|
||||
def test_incompatible_plugin_outside_the_addons_is_disabled(self):
|
||||
plan = nextcloud_plugin_plan(
|
||||
_items(
|
||||
(
|
||||
"oidc_login",
|
||||
{
|
||||
"enabled": True,
|
||||
"config": {
|
||||
"incompatible_plugins": ["user_oidc", "sociallogin"]
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
_apps(enabled=("oidc_login", "user_oidc")),
|
||||
)
|
||||
self.assertEqual(plan["disable"], ["user_oidc"])
|
||||
self.assertEqual(plan["configure"], ["oidc_login"])
|
||||
|
||||
def test_string_flags_from_templated_config(self):
|
||||
plan = nextcloud_plugin_plan(
|
||||
_items(("deck", {"enabled": "True"}), ("news", {"enabled": "False"})),
|
||||
_apps(enabled=("deck", "news")),
|
||||
)
|
||||
self.assertEqual(plan["configure"], ["deck"])
|
||||
self.assertEqual(plan["disable"], ["news"])
|
||||
|
||||
def test_empty_app_list_installs_every_wanted_plugin(self):
|
||||
plan = nextcloud_plugin_plan(_items(("deck", {"enabled": True})), {})
|
||||
self.assertEqual(plan["install"], ["deck"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user