bitool 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bitool/__init__.py +27 -0
- bitool/cmd/__init__.py +65 -0
- bitool/cmd/_base.py +105 -0
- bitool/cmd/_condition.py +60 -0
- bitool/cmd/_scheduler.py +548 -0
- bitool/cmd/env.py +454 -0
- bitool/cmd/git.py +123 -0
- bitool/cmd/io.py +248 -0
- bitool/cmd/pdf.py +385 -0
- bitool/cmd/run.py +300 -0
- bitool/cmd/toml.py +237 -0
- bitool/cmd/version.py +630 -0
- bitool/consts.py +14 -0
- bitool/core/__init__.py +7 -0
- bitool/core/app.py +142 -0
- bitool/core/commands.py +194 -0
- bitool/core/config.py +647 -0
- bitool/core/env.py +18 -0
- bitool/core/logger.py +237 -0
- bitool/core/plugin.py +117 -0
- bitool/core/workspace.py +76 -0
- bitool/models/__init__.py +3 -0
- bitool/models/version.py +173 -0
- bitool/scripts/__init__.py +1 -0
- bitool/scripts/bumpversion.py +189 -0
- bitool/scripts/clearscreen.py +37 -0
- bitool/scripts/envpy.py +161 -0
- bitool/scripts/envrs.py +119 -0
- bitool/scripts/filedate.py +246 -0
- bitool/scripts/filelevel.py +191 -0
- bitool/scripts/gittool.py +178 -0
- bitool/scripts/img2pdf.py +151 -0
- bitool/scripts/pdf2img.py +139 -0
- bitool/scripts/piptool.py +130 -0
- bitool/scripts/pymake.py +345 -0
- bitool/scripts/sshcopyid.py +491 -0
- bitool/scripts/taskkill.py +366 -0
- bitool/scripts/which.py +227 -0
- bitool/types.py +7 -0
- bitool/utils/__init__.py +9 -0
- bitool/utils/cli_parser.py +412 -0
- bitool/utils/executor.py +881 -0
- bitool/utils/profiler.py +369 -0
- bitool/utils/task.py +133 -0
- bitool/utils/task_group.py +668 -0
- bitool/utils/tests/__init__.py +0 -0
- bitool/utils/tests/test_profiler.py +487 -0
- bitool-0.1.2.dist-info/METADATA +154 -0
- bitool-0.1.2.dist-info/RECORD +51 -0
- bitool-0.1.2.dist-info/WHEEL +4 -0
- bitool-0.1.2.dist-info/entry_points.txt +15 -0
bitool/core/app.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""核心应用入口 - 协调 GUI 和 Web 两种模式."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .commands import CommandCategory, CommandRegistry
|
|
9
|
+
from .plugin import PluginContext
|
|
10
|
+
from .plugin import PluginRegistry as PluginRegistryCore
|
|
11
|
+
from .workspace import WorkspaceManager
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BitoolApp:
|
|
15
|
+
"""Bitool 主应用."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config: Any = None) -> None:
|
|
18
|
+
"""初始化应用.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
config: 应用配置(可选)
|
|
22
|
+
"""
|
|
23
|
+
self._config = config
|
|
24
|
+
self._workspace = WorkspaceManager()
|
|
25
|
+
self._plugin_registry = PluginRegistryCore()
|
|
26
|
+
self._command_registry = CommandRegistry()
|
|
27
|
+
|
|
28
|
+
# 设置插件上下文
|
|
29
|
+
self._plugin_context = PluginContext(
|
|
30
|
+
workspace=self._workspace,
|
|
31
|
+
config=self._config,
|
|
32
|
+
registry=self._plugin_registry,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def config(self) -> Any:
|
|
37
|
+
"""获取配置."""
|
|
38
|
+
return self._config
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def workspace(self) -> WorkspaceManager:
|
|
42
|
+
"""获取工作空间管理器."""
|
|
43
|
+
return self._workspace
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def registry(self) -> CommandRegistry:
|
|
47
|
+
"""获取命令注册表."""
|
|
48
|
+
return self._command_registry
|
|
49
|
+
|
|
50
|
+
def start(self, mode: str = "gui") -> None:
|
|
51
|
+
"""启动应用.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
mode: 运行模式 (gui/web)
|
|
55
|
+
"""
|
|
56
|
+
# 加载插件
|
|
57
|
+
self._load_plugins()
|
|
58
|
+
|
|
59
|
+
# 注册内建命令
|
|
60
|
+
self._register_builtin_commands()
|
|
61
|
+
|
|
62
|
+
# 创建模式
|
|
63
|
+
if mode == "gui":
|
|
64
|
+
self._run_gui()
|
|
65
|
+
elif mode == "web":
|
|
66
|
+
self._run_web()
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError(f"未知模式: {mode},支持的模式: gui, web")
|
|
69
|
+
|
|
70
|
+
def _run_gui(self) -> None:
|
|
71
|
+
"""运行 GUI 模式."""
|
|
72
|
+
# TODO: 实现 GUI 启动逻辑
|
|
73
|
+
|
|
74
|
+
def _run_web(self, host: str = "127.0.0.1", port: int = 8000) -> None:
|
|
75
|
+
"""运行 Web 模式.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
host: 监听地址
|
|
79
|
+
port: 监听端口
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
# TODO: 实现 Web 启动逻辑
|
|
83
|
+
|
|
84
|
+
def _load_plugins(self) -> None:
|
|
85
|
+
"""加载插件."""
|
|
86
|
+
# 从配置目录加载插件
|
|
87
|
+
plugin_dirs = ["~/.bitool/plugins"]
|
|
88
|
+
if self._config and hasattr(self._config, "plugin_dirs"):
|
|
89
|
+
plugin_dirs = self._config.plugin_dirs
|
|
90
|
+
|
|
91
|
+
for plugin_dir in plugin_dirs:
|
|
92
|
+
self._plugin_registry.load_plugins_from_directory(plugin_dir)
|
|
93
|
+
|
|
94
|
+
# 初始化所有插件
|
|
95
|
+
for plugin_name in self._plugin_registry.list_plugins():
|
|
96
|
+
plugin = self._plugin_registry.get_plugin(plugin_name)
|
|
97
|
+
if plugin and hasattr(plugin, "initialize"):
|
|
98
|
+
plugin.initialize(self._plugin_context)
|
|
99
|
+
|
|
100
|
+
def _register_builtin_commands(self) -> None:
|
|
101
|
+
"""注册内建命令."""
|
|
102
|
+
|
|
103
|
+
def system_info(**kwargs: Any) -> str:
|
|
104
|
+
"""显示系统信息."""
|
|
105
|
+
plugins = ", ".join(self._plugin_registry.list_plugins()) or "无"
|
|
106
|
+
return f"Bitool Maturin v0.1.0\n工作空间: {self.workspace.root}\n插件: {plugins}"
|
|
107
|
+
|
|
108
|
+
self.registry.register(
|
|
109
|
+
name="system_info",
|
|
110
|
+
description="显示系统信息",
|
|
111
|
+
category=CommandCategory.SYSTEM,
|
|
112
|
+
handler=system_info,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def health_check(**kwargs: Any) -> str:
|
|
116
|
+
"""系统健康检查."""
|
|
117
|
+
issues = []
|
|
118
|
+
|
|
119
|
+
# 检查工作空间
|
|
120
|
+
workspace_root = self.workspace.root
|
|
121
|
+
if workspace_root and not Path(workspace_root).exists():
|
|
122
|
+
issues.append(f"工作空间目录不存在: {workspace_root}")
|
|
123
|
+
|
|
124
|
+
if issues:
|
|
125
|
+
return "健康检查发现问题:\n" + "\n".join(f" - {issue}" for issue in issues)
|
|
126
|
+
return "系统健康状态: 正常"
|
|
127
|
+
|
|
128
|
+
self.registry.register(
|
|
129
|
+
name="health_check",
|
|
130
|
+
description="系统健康检查",
|
|
131
|
+
category=CommandCategory.SYSTEM,
|
|
132
|
+
handler=health_check,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def run(self, mode: str = "gui", **kwargs: Any) -> None:
|
|
136
|
+
"""运行应用 (同步入口).
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
mode: 运行模式
|
|
140
|
+
**kwargs: 其他参数
|
|
141
|
+
"""
|
|
142
|
+
self.start(mode)
|
bitool/core/commands.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""命令注册与执行系统."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import inspect
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any, Callable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CommandCategory(str, Enum):
|
|
13
|
+
"""命令类别."""
|
|
14
|
+
|
|
15
|
+
PDF = "pdf"
|
|
16
|
+
WORKSPACE = "workspace"
|
|
17
|
+
SYSTEM = "system"
|
|
18
|
+
FILE = "file"
|
|
19
|
+
PLUGIN = "plugin"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class CommandResult:
|
|
24
|
+
"""命令执行结果."""
|
|
25
|
+
|
|
26
|
+
success: bool
|
|
27
|
+
output: str = ""
|
|
28
|
+
error: str = ""
|
|
29
|
+
data: Any = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class CommandInfo:
|
|
34
|
+
"""命令信息."""
|
|
35
|
+
|
|
36
|
+
name: str
|
|
37
|
+
description: str
|
|
38
|
+
category: CommandCategory
|
|
39
|
+
handler: Callable
|
|
40
|
+
parameters: dict[str, Any] = field(default_factory=dict)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CommandRegistry:
|
|
44
|
+
"""命令注册表."""
|
|
45
|
+
|
|
46
|
+
def __init__(self) -> None:
|
|
47
|
+
"""初始化命令注册表."""
|
|
48
|
+
self._commands: dict[str, CommandInfo] = {}
|
|
49
|
+
|
|
50
|
+
def register(
|
|
51
|
+
self,
|
|
52
|
+
name: str,
|
|
53
|
+
description: str,
|
|
54
|
+
category: CommandCategory,
|
|
55
|
+
handler: Callable,
|
|
56
|
+
parameters: dict[str, Any] | None = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""注册命令.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
name: 命令名称
|
|
62
|
+
description: 命令描述
|
|
63
|
+
category: 命令类别
|
|
64
|
+
handler: 命令处理器
|
|
65
|
+
parameters: 命令参数
|
|
66
|
+
"""
|
|
67
|
+
if name in self._commands:
|
|
68
|
+
raise ValueError(f"命令 {name} 已注册")
|
|
69
|
+
|
|
70
|
+
self._commands[name] = CommandInfo(
|
|
71
|
+
name=name,
|
|
72
|
+
description=description,
|
|
73
|
+
category=category,
|
|
74
|
+
handler=handler,
|
|
75
|
+
parameters=parameters or {},
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def unregister(self, name: str) -> None:
|
|
79
|
+
"""注销命令.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
name: 命令名称
|
|
83
|
+
"""
|
|
84
|
+
self._commands.pop(name, None)
|
|
85
|
+
|
|
86
|
+
def get(self, name: str) -> CommandInfo | None:
|
|
87
|
+
"""获取命令信息.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
name: 命令名称
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
命令信息,如果不存在则返回 None
|
|
94
|
+
"""
|
|
95
|
+
return self._commands.get(name)
|
|
96
|
+
|
|
97
|
+
def list_commands(self, category: CommandCategory | None = None) -> list[CommandInfo]:
|
|
98
|
+
"""列出命令.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
category: 命令类别(可选)
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
命令信息列表
|
|
105
|
+
"""
|
|
106
|
+
if category is None:
|
|
107
|
+
return list(self._commands.values())
|
|
108
|
+
return [cmd for cmd in self._commands.values() if cmd.category == category]
|
|
109
|
+
|
|
110
|
+
def list(self, category: CommandCategory | None = None) -> list[CommandInfo]:
|
|
111
|
+
"""列出命令 (别名)."""
|
|
112
|
+
return self.list_commands(category)
|
|
113
|
+
|
|
114
|
+
def list_names(self, category: CommandCategory | None = None) -> list[str]:
|
|
115
|
+
"""列出命令名称.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
category: 命令类别(可选)
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
命令名称列表
|
|
122
|
+
"""
|
|
123
|
+
return [cmd.name for cmd in self.list_commands(category)]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class CommandExecutor:
|
|
127
|
+
"""命令执行器."""
|
|
128
|
+
|
|
129
|
+
def __init__(self, registry: CommandRegistry) -> None:
|
|
130
|
+
"""初始化命令执行器.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
registry: 命令注册表
|
|
134
|
+
"""
|
|
135
|
+
self._registry = registry
|
|
136
|
+
|
|
137
|
+
async def execute(
|
|
138
|
+
self,
|
|
139
|
+
name: str,
|
|
140
|
+
**kwargs: Any,
|
|
141
|
+
) -> CommandResult:
|
|
142
|
+
"""执行命令.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
name: 命令名称
|
|
146
|
+
**kwargs: 命令参数
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
命令执行结果
|
|
150
|
+
"""
|
|
151
|
+
cmd_info = self._registry.get(name)
|
|
152
|
+
if cmd_info is None:
|
|
153
|
+
return CommandResult(
|
|
154
|
+
success=False,
|
|
155
|
+
error=f"命令 '{name}' 不存在",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
handler = cmd_info.handler
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
# 判断是否是异步函数
|
|
162
|
+
if inspect.iscoroutinefunction(handler):
|
|
163
|
+
result = await handler(**kwargs)
|
|
164
|
+
else:
|
|
165
|
+
# 在事件循环中运行同步函数
|
|
166
|
+
loop = asyncio.get_event_loop()
|
|
167
|
+
result = await loop.run_in_executor(None, lambda: handler(**kwargs))
|
|
168
|
+
|
|
169
|
+
if isinstance(result, CommandResult):
|
|
170
|
+
return result
|
|
171
|
+
return CommandResult(success=True, output=str(result))
|
|
172
|
+
|
|
173
|
+
except Exception as e: # noqa: BLE001
|
|
174
|
+
return CommandResult(
|
|
175
|
+
success=False,
|
|
176
|
+
error=f"执行命令 '{name}' 时出错: {e}",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def execute_sync(self, name: str, **kwargs: Any) -> CommandResult:
|
|
180
|
+
"""同步执行命令 (用于本地模式).
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
name: 命令名称
|
|
184
|
+
**kwargs: 命令参数
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
命令执行结果
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
return asyncio.run(self.execute(name, **kwargs))
|
|
191
|
+
except RuntimeError:
|
|
192
|
+
# 如果已有事件循环运行,使用当前循环
|
|
193
|
+
loop = asyncio.get_event_loop()
|
|
194
|
+
return loop.run_until_complete(self.execute(name, **kwargs))
|