This commit is contained in:
墨梓柒
2025-06-19 23:15:53 +08:00
9 changed files with 241 additions and 308 deletions

View File

@@ -19,7 +19,6 @@ project_root = Path(__file__).parent.parent.parent.parent
sys.path.insert(0, str(project_root))
logger = get_logger("manifest_tool")
@@ -47,9 +46,7 @@ def create_minimal_manifest(plugin_dir: str, plugin_name: str, description: str
"name": plugin_name,
"version": "1.0.0",
"description": description or f"{plugin_name}插件",
"author": {
"name": author or "Unknown"
}
"author": {"name": author or "Unknown"},
}
try:
@@ -84,15 +81,9 @@ def create_complete_manifest(plugin_dir: str, plugin_name: str) -> bool:
"name": plugin_name,
"version": "1.0.0",
"description": f"{plugin_name}插件描述",
"author": {
"name": "插件作者",
"url": "https://github.com/your-username"
},
"author": {"name": "插件作者", "url": "https://github.com/your-username"},
"license": "MIT",
"host_application": {
"min_version": "1.0.0",
"max_version": "4.0.0"
},
"host_application": {"min_version": "1.0.0", "max_version": "4.0.0"},
"homepage_url": "https://github.com/your-repo",
"repository_url": "https://github.com/your-repo",
"keywords": ["keyword1", "keyword2"],
@@ -102,14 +93,8 @@ def create_complete_manifest(plugin_dir: str, plugin_name: str) -> bool:
"plugin_info": {
"is_built_in": False,
"plugin_type": "general",
"components": [
{
"type": "action",
"name": "sample_action",
"description": "示例动作组件"
}
]
}
"components": [{"type": "action", "name": "sample_action", "description": "示例动作组件"}],
},
}
try:
@@ -176,7 +161,7 @@ def scan_plugins_without_manifest(root_dir: str) -> None:
for root, dirs, files in os.walk(root_dir):
# 跳过隐藏目录和__pycache__
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
dirs[:] = [d for d in dirs if not d.startswith(".") and d != "__pycache__"]
# 检查是否包含plugin.py文件标识为插件目录
if "plugin.py" in files:
@@ -228,12 +213,7 @@ def main():
try:
if args.command == "create-minimal":
plugin_name = args.name or os.path.basename(os.path.abspath(args.plugin_dir))
success = create_minimal_manifest(
args.plugin_dir,
plugin_name,
args.description or "",
args.author or ""
)
success = create_minimal_manifest(args.plugin_dir, plugin_name, args.description or "", args.author or "")
sys.exit(0 if success else 1)
elif args.command == "create-complete":

View File

@@ -89,11 +89,11 @@ def test_current_version():
print(f" ✅ 当前主机版本: {current_version}")
# 验证版本号格式
parts = current_version.split('.')
parts = current_version.split(".")
if len(parts) == 3 and all(part.isdigit() for part in parts):
print(f" ✅ 版本号格式正确")
print(" ✅ 版本号格式正确")
else:
print(f" ❌ 版本号格式错误")
print(" ❌ 版本号格式错误")
except Exception as e:
print(f" ❌ 获取当前版本失败: {e}")
@@ -105,31 +105,13 @@ def test_manifest_compatibility():
# 模拟manifest数据
test_manifests = [
{
"name": "兼容插件",
"host_application": {
"min_version": "0.1.0",
"max_version": "2.0.0"
}
},
{
"name": "版本过高插件",
"host_application": {
"min_version": "10.0.0",
"max_version": "20.0.0"
}
},
{
"name": "版本过低插件",
"host_application": {
"min_version": "0.1.0",
"max_version": "0.2.0"
}
},
{"name": "兼容插件", "host_application": {"min_version": "0.1.0", "max_version": "2.0.0"}},
{"name": "版本过高插件", "host_application": {"min_version": "10.0.0", "max_version": "20.0.0"}},
{"name": "版本过低插件", "host_application": {"min_version": "0.1.0", "max_version": "0.2.0"}},
{
"name": "无版本要求插件",
# 没有host_application字段
}
},
]
# 这里需要导入PluginManager来测试但可能会有依赖问题
@@ -144,9 +126,7 @@ def test_manifest_compatibility():
min_version = host_app.get("min_version", "")
max_version = host_app.get("max_version", "")
is_compatible, error_msg = VersionComparator.is_version_in_range(
current_version, min_version, max_version
)
is_compatible, error_msg = VersionComparator.is_version_in_range(current_version, min_version, max_version)
status = "" if is_compatible else ""
print(f" {status} {plugin_name}: {is_compatible}")
@@ -166,7 +146,6 @@ def test_additional_snapshot_formats():
("0.8.0-snapshot.2", "0.8.0"),
("0.8.0", "0.8.0"),
("0.9.0-snapshot.1", "0.9.0"),
# 边界情况
("1.0.0-snapshot.999", "1.0.0"),
("2.15.3-snapshot.42", "2.15.3"),
@@ -193,11 +172,9 @@ def test_snapshot_version_comparison():
("0.8.0-snapshot.2", "0.8.0", 0), # 应该相等
("0.9.0-snapshot.1", "0.8.0", 1), # 应该大于
("0.7.0-snapshot.1", "0.8.0", -1), # 应该小于
# snapshot版本之间比较
("0.8.0-snapshot.1", "0.8.0-snapshot.2", 0), # 都标准化为0.8.0,相等
("0.9.0-snapshot.1", "0.8.0-snapshot.1", 1), # 0.9.0 > 0.8.0
# 边界情况
("1.0.0-snapshot.1", "0.9.9", 1), # 主版本更高
("0.9.0-snapshot.1", "0.8.99", 1), # 次版本更高
@@ -229,6 +206,7 @@ def main():
except Exception as e:
print(f"\n❌ 测试过程中发生错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

View File

@@ -28,7 +28,7 @@ from src.plugin_system.utils import (
ManifestValidator,
ManifestGenerator,
validate_plugin_manifest,
generate_plugin_manifest
generate_plugin_manifest,
)

View File

@@ -183,19 +183,13 @@ class BasePlugin(ABC):
"name": self.plugin_name,
"version": self.plugin_version,
"description": self.plugin_description or "插件描述",
"author": {
"name": self.plugin_author or "Unknown",
"url": ""
},
"author": {"name": self.plugin_author or "Unknown", "url": ""},
"license": "MIT",
"host_application": {
"min_version": "1.0.0",
"max_version": "4.0.0"
},
"host_application": {"min_version": "1.0.0", "max_version": "4.0.0"},
"keywords": [],
"categories": [],
"default_locale": "zh-CN",
"locales_path": "_locales"
"locales_path": "_locales",
}
try:

View File

@@ -77,6 +77,7 @@ class PluginManager:
# 第二阶段:实例化所有已注册的插件类
from src.plugin_system.base.base_plugin import get_registered_plugin_classes
plugin_classes = get_registered_plugin_classes()
total_registered = 0
total_failed_registration = 0
@@ -543,9 +544,7 @@ class PluginManager:
from src.plugin_system.utils.manifest_utils import VersionComparator
current_version = VersionComparator.get_current_host_version()
is_compatible, error_msg = VersionComparator.is_version_in_range(
current_version, min_version, max_version
)
is_compatible, error_msg = VersionComparator.is_version_in_range(current_version, min_version, max_version)
if not is_compatible:
return False, f"版本不兼容: {error_msg}"
@@ -557,6 +556,7 @@ class PluginManager:
logger.warning(f"插件 {plugin_name} 版本兼容性检查失败: {e}")
return True, "" # 检查失败时默认允许加载
# 全局插件管理器实例
plugin_manager = PluginManager()

View File

@@ -8,12 +8,7 @@ from src.plugin_system.utils.manifest_utils import (
ManifestValidator,
ManifestGenerator,
validate_plugin_manifest,
generate_plugin_manifest
generate_plugin_manifest,
)
__all__ = [
"ManifestValidator",
"ManifestGenerator",
"validate_plugin_manifest",
"generate_plugin_manifest"
]
__all__ = ["ManifestValidator", "ManifestGenerator", "validate_plugin_manifest", "generate_plugin_manifest"]

View File

@@ -7,7 +7,7 @@
import json
import os
import re
from typing import Dict, Any, Optional, Tuple, List
from typing import Dict, Any, Optional, Tuple
from src.common.logger import get_logger
from src.config.config import MMC_VERSION
@@ -34,18 +34,18 @@ class VersionComparator:
return "0.0.0"
# 移除snapshot部分
normalized = re.sub(r'-snapshot\.\d+', '', version.strip())
normalized = re.sub(r"-snapshot\.\d+", "", version.strip())
# 确保版本号格式正确
if not re.match(r'^\d+(\.\d+){0,2}$', normalized):
if not re.match(r"^\d+(\.\d+){0,2}$", normalized):
# 如果不是有效的版本号格式,返回默认版本
return "0.0.0"
# 尝试补全版本号
parts = normalized.split('.')
parts = normalized.split(".")
while len(parts) < 3:
parts.append('0')
normalized = '.'.join(parts[:3])
parts.append("0")
normalized = ".".join(parts[:3])
return normalized
@@ -61,7 +61,7 @@ class VersionComparator:
"""
normalized = VersionComparator.normalize_version(version)
try:
parts = normalized.split('.')
parts = normalized.split(".")
return (int(parts[0]), int(parts[1]), int(parts[2]))
except (ValueError, IndexError):
logger.warning(f"无法解析版本号: {version},使用默认版本 0.0.0")
@@ -133,13 +133,7 @@ class ManifestValidator:
"""Manifest文件验证器"""
# 必需字段(必须存在且不能为空)
REQUIRED_FIELDS = [
"manifest_version",
"name",
"version",
"description",
"author"
]
REQUIRED_FIELDS = ["manifest_version", "name", "version", "description", "author"]
# 可选字段(可以不存在或为空)
OPTIONAL_FIELDS = [
@@ -151,15 +145,11 @@ class ManifestValidator:
"categories",
"default_locale",
"locales_path",
"plugin_info"
"plugin_info",
]
# 建议填写的字段(会给出警告但不会导致验证失败)
RECOMMENDED_FIELDS = [
"license",
"keywords",
"categories"
]
RECOMMENDED_FIELDS = ["license", "keywords", "categories"]
SUPPORTED_MANIFEST_VERSIONS = [3]
@@ -190,7 +180,9 @@ class ManifestValidator:
if "manifest_version" in manifest_data:
version = manifest_data["manifest_version"]
if version not in self.SUPPORTED_MANIFEST_VERSIONS:
self.validation_errors.append(f"不支持的manifest版本: {version},支持的版本: {self.SUPPORTED_MANIFEST_VERSIONS}")
self.validation_errors.append(
f"不支持的manifest版本: {version},支持的版本: {self.SUPPORTED_MANIFEST_VERSIONS}"
)
# 检查作者信息格式
if "author" in manifest_data:
@@ -230,7 +222,9 @@ class ManifestValidator:
if not is_compatible:
self.validation_errors.append(f"版本兼容性检查失败: {error_msg} (当前版本: {current_version})")
else:
logger.debug(f"版本兼容性检查通过: 当前版本 {current_version} 符合要求 [{min_version}, {max_version}]")
logger.debug(
f"版本兼容性检查通过: 当前版本 {current_version} 符合要求 [{min_version}, {max_version}]"
)
else:
self.validation_errors.append("host_application格式错误应为对象")
@@ -275,7 +269,9 @@ class ManifestValidator:
# 检查组件必需字段
for comp_field in ["type", "name", "description"]:
if comp_field not in component or not component[comp_field]:
self.validation_errors.append(f"plugin_info.components[{i}]缺少必需字段: {comp_field}")
self.validation_errors.append(
f"plugin_info.components[{i}]缺少必需字段: {comp_field}"
)
else:
self.validation_errors.append("plugin_info应为对象格式")
@@ -310,21 +306,15 @@ class ManifestGenerator:
"name": "",
"version": "1.0.0",
"description": "",
"author": {
"name": "",
"url": ""
},
"author": {"name": "", "url": ""},
"license": "MIT",
"host_application": {
"min_version": "1.0.0",
"max_version": "4.0.0"
},
"host_application": {"min_version": "1.0.0", "max_version": "4.0.0"},
"homepage_url": "",
"repository_url": "",
"keywords": [],
"categories": [],
"default_locale": "zh-CN",
"locales_path": "_locales"
"locales_path": "_locales",
}
def generate_from_plugin(self, plugin_instance) -> Dict[str, Any]:
@@ -355,31 +345,27 @@ class ManifestGenerator:
component_data = {
"type": component_info.component_type.value,
"name": component_info.name,
"description": component_info.description
"description": component_info.description,
}
# 添加激活模式信息对于Action组件
if hasattr(component_class, 'focus_activation_type'):
if hasattr(component_class, "focus_activation_type"):
activation_modes = []
if hasattr(component_class, 'focus_activation_type'):
if hasattr(component_class, "focus_activation_type"):
activation_modes.append(component_class.focus_activation_type.value)
if hasattr(component_class, 'normal_activation_type'):
if hasattr(component_class, "normal_activation_type"):
activation_modes.append(component_class.normal_activation_type.value)
component_data["activation_modes"] = list(set(activation_modes))
# 添加关键词信息
if hasattr(component_class, 'activation_keywords'):
keywords = getattr(component_class, 'activation_keywords', [])
if hasattr(component_class, "activation_keywords"):
keywords = getattr(component_class, "activation_keywords", [])
if keywords:
component_data["keywords"] = keywords
components.append(component_data)
manifest["plugin_info"] = {
"is_built_in": True,
"plugin_type": "general",
"components": components
}
manifest["plugin_info"] = {"is_built_in": True, "plugin_type": "general", "components": components}
return manifest