mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-06 15:22:05 +08:00
refactor(plugin): 移除已无调用者的物理分身源码改写器 (#6683)
物理分身是早期实现:复制整个插件目录,再用字符串替换改写副本源码里的类名、
plugin_config_prefix 和联邦构建产物。虚拟实例接管后,分身不再复制目录,
由装载器改写类身份、按实例 ID 隔离配置与数据,这套改写器随之失去调用者。
求证依据(全仓 git grep,覆盖 app/、tests/、scripts/、docs/、skills/):
- PluginPackageManager.clone() 无任何生产调用者。分身的唯一生产路径是
POST /api/v1/plugin/clone/{plugin_id} -> PluginManager.clone_plugin()
-> PluginCloneService.clone(),后者只写 PluginInstance 记录与隔离配置,
不碰包适配器。clone() 也没有经 PluginSystemServices 暴露出去。
- clone() 的四个私有实现 _modify_plugin_files / _modify_python_file /
_modify_federation_files / _rename_federation_assets,消费者只有 clone()
自身与 PluginSystemServices 的同名透传。
- PluginSystemServices 的四个透传,消费者只有 PluginManager 的 _modify_* shim。
- PluginManager 的四个 shim 无任何调用者。动态可达性已单独排查:
全仓没有 getattr/字符串反射指向这些名字;app/runtime/compat/manifest.py
不登记它们的别名(只有 app.core.plugin -> 本模块的模块级映射);
app/sdk/ 不再导出;PluginManager 与 PluginPackageManager 都没有
__getattr__ 兜底,属性不存在即 AttributeError;官方插件基线
official-plugin-baseline.json 零命中。
- @observe_compat_facade("PluginManager") 只包装类上已存在的方法,
不会凭空合成属性,因此 shim 删除后 enforce_facade 再也匹配不到
notices.py 里那四条 key,登记随之成为不可达数据,一并删除。
替代路径:这四条弃用声明当初承诺的替代目标是
get_plugin_system().package._modify_*(),那是一次「门面搬到适配器」的
重定位登记,本次连同能力一起下线;分身能力本身的替代路径是虚拟实例
PluginCloneService.clone(),它已在生产链路上,见
docs/v2-to-v3-overview.md §3.6「不复制插件源码,也能保持各实例配置隔离」。
既有磁盘上的旧物理分身不受影响:卸载路径读取 is_clone 属性并调用
remove_plugin_package() 的逻辑原样保留,只是不再产生新的物理分身。
这是对已公告弃用 API(DeprecationStage.SILENT,since v3.0.0)的正式移除。
连带改动:
- package.py 的 import re 仅服务于 _modify_python_file,同步移除;模块
docstring 去掉「分身处理」。
- system.py 的 typing.cast 仅服务于被删透传,同步移除。
- tests/test_plugin_package_manager.py::test_clone_rewrites_python_and_federation_assets
是这套改写器的唯一测试,且只覆盖已无调用者的路径,随实现一并删除。
(删的是测试函数不是测试文件,tests/run.py 的分片装箱不变。)
- mypy 低水位随实现下降:app/runtime/extensions/plugin/manager.py 的
assignment 8->4(四个 shim 的 version/icon 参数 str = None)、
no-untyped-def 12->11(_rename_federation_assets 缺返回标注),
fixture 与 docs/refactor/optimization-checklist.md 的全量 mypy 计数
9,371 -> 9,366 同步更新。依赖、复杂度、ruff、并发等其余基线无变化。
Co-authored-by: jxxghp <jxxghp@gmail.com>
This commit is contained in:
@@ -1460,69 +1460,3 @@ class PluginManager(ConfigReloadMixin, metaclass=Singleton):
|
||||
:raise LookupError: 插件不存在,或 plugin_id 实为某个分身自身的实例ID
|
||||
"""
|
||||
self._plugin_default_target.clear_target(plugin_id, instance_id)
|
||||
|
||||
def _modify_plugin_files(self, plugin_dir: Path, original_id: str, suffix: str,
|
||||
name: str, description: str, version: str = None,
|
||||
icon: str = None) -> Tuple[bool, str]:
|
||||
"""
|
||||
兼容旧内部调用,将分身文件改写委托给包适配器。
|
||||
:param plugin_dir: 插件目录
|
||||
:param original_id: 原插件ID
|
||||
:param suffix: 分身后缀
|
||||
:param name: 分身名称
|
||||
:param description: 分身描述
|
||||
:param version: 自定义版本号
|
||||
:param icon: 自定义图标URL
|
||||
:return: (是否成功, 错误信息)
|
||||
"""
|
||||
original_plugin_class = self._plugins.get(original_id)
|
||||
if not original_plugin_class:
|
||||
return False, f"无法获取原插件类 {original_id}"
|
||||
return self._plugin_runtime.system().modify_plugin_files(
|
||||
plugin_dir=plugin_dir,
|
||||
original_class_name=original_plugin_class.__name__,
|
||||
suffix=suffix,
|
||||
name=name,
|
||||
description=description,
|
||||
version=version,
|
||||
icon=icon,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _modify_python_file(file_path: Path, original_class_name: str,
|
||||
clone_class_name: str, name: str, description: str,
|
||||
version: str = None, icon: str = None) -> Tuple[bool, str]:
|
||||
"""
|
||||
兼容旧内部调用,将 Python 文件改写委托给包适配器。
|
||||
"""
|
||||
return PluginManager()._plugin_runtime.system().modify_python_file(
|
||||
file_path=file_path,
|
||||
original_class_name=original_class_name,
|
||||
clone_class_name=clone_class_name,
|
||||
name=name,
|
||||
description=description,
|
||||
version=version,
|
||||
icon=icon,
|
||||
)
|
||||
|
||||
def _modify_federation_files(self, dist_dir: Path, original_class_name: str,
|
||||
clone_class_name: str) -> Tuple[bool, str]:
|
||||
"""
|
||||
兼容旧内部调用,将联邦文件改写委托给包适配器。
|
||||
"""
|
||||
return self._plugin_runtime.system().modify_federation_files(
|
||||
dist_dir=dist_dir,
|
||||
original_class_name=original_class_name,
|
||||
clone_class_name=clone_class_name,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _rename_federation_assets(dist_dir: Path, original_class_name: str, clone_class_name: str):
|
||||
"""
|
||||
兼容旧内部调用,将资源重命名委托给包适配器。
|
||||
"""
|
||||
PluginManager()._plugin_runtime.system().rename_federation_assets(
|
||||
dist_dir,
|
||||
original_class_name,
|
||||
clone_class_name,
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional, cast
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
class PluginSystemServices:
|
||||
@@ -95,34 +95,6 @@ class PluginSystemServices:
|
||||
"""通过唯一包事务 owner 删除插件物理目录。"""
|
||||
return bool(self.package.remove_plugin(plugin_id))
|
||||
|
||||
def modify_plugin_files(self, **kwargs: Any) -> tuple[bool, str]:
|
||||
"""把旧分身源码改写调用收口到唯一包适配器。"""
|
||||
return cast(tuple[bool, str], self.package._modify_plugin_files(**kwargs))
|
||||
|
||||
def modify_python_file(self, **kwargs: Any) -> tuple[bool, str]:
|
||||
"""把旧 Python 类改写调用收口到唯一包适配器。"""
|
||||
return cast(tuple[bool, str], self.package._modify_python_file(**kwargs))
|
||||
|
||||
def modify_federation_files(self, **kwargs: Any) -> tuple[bool, str]:
|
||||
"""把旧联邦构建产物改写调用收口到唯一包适配器。"""
|
||||
return cast(
|
||||
tuple[bool, str],
|
||||
self.package._modify_federation_files(**kwargs),
|
||||
)
|
||||
|
||||
def rename_federation_assets(
|
||||
self,
|
||||
dist_dir: Path,
|
||||
original_class_name: str,
|
||||
clone_class_name: str,
|
||||
) -> None:
|
||||
"""把旧联邦资源重命名调用收口到唯一包适配器。"""
|
||||
self.package._rename_federation_assets(
|
||||
dist_dir,
|
||||
original_class_name,
|
||||
clone_class_name,
|
||||
)
|
||||
|
||||
|
||||
_services: Optional[PluginSystemServices] = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user