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.
Files changed (51) hide show
  1. bitool/__init__.py +27 -0
  2. bitool/cmd/__init__.py +65 -0
  3. bitool/cmd/_base.py +105 -0
  4. bitool/cmd/_condition.py +60 -0
  5. bitool/cmd/_scheduler.py +548 -0
  6. bitool/cmd/env.py +454 -0
  7. bitool/cmd/git.py +123 -0
  8. bitool/cmd/io.py +248 -0
  9. bitool/cmd/pdf.py +385 -0
  10. bitool/cmd/run.py +300 -0
  11. bitool/cmd/toml.py +237 -0
  12. bitool/cmd/version.py +630 -0
  13. bitool/consts.py +14 -0
  14. bitool/core/__init__.py +7 -0
  15. bitool/core/app.py +142 -0
  16. bitool/core/commands.py +194 -0
  17. bitool/core/config.py +647 -0
  18. bitool/core/env.py +18 -0
  19. bitool/core/logger.py +237 -0
  20. bitool/core/plugin.py +117 -0
  21. bitool/core/workspace.py +76 -0
  22. bitool/models/__init__.py +3 -0
  23. bitool/models/version.py +173 -0
  24. bitool/scripts/__init__.py +1 -0
  25. bitool/scripts/bumpversion.py +189 -0
  26. bitool/scripts/clearscreen.py +37 -0
  27. bitool/scripts/envpy.py +161 -0
  28. bitool/scripts/envrs.py +119 -0
  29. bitool/scripts/filedate.py +246 -0
  30. bitool/scripts/filelevel.py +191 -0
  31. bitool/scripts/gittool.py +178 -0
  32. bitool/scripts/img2pdf.py +151 -0
  33. bitool/scripts/pdf2img.py +139 -0
  34. bitool/scripts/piptool.py +130 -0
  35. bitool/scripts/pymake.py +345 -0
  36. bitool/scripts/sshcopyid.py +491 -0
  37. bitool/scripts/taskkill.py +366 -0
  38. bitool/scripts/which.py +227 -0
  39. bitool/types.py +7 -0
  40. bitool/utils/__init__.py +9 -0
  41. bitool/utils/cli_parser.py +412 -0
  42. bitool/utils/executor.py +881 -0
  43. bitool/utils/profiler.py +369 -0
  44. bitool/utils/task.py +133 -0
  45. bitool/utils/task_group.py +668 -0
  46. bitool/utils/tests/__init__.py +0 -0
  47. bitool/utils/tests/test_profiler.py +487 -0
  48. bitool-0.1.2.dist-info/METADATA +154 -0
  49. bitool-0.1.2.dist-info/RECORD +51 -0
  50. bitool-0.1.2.dist-info/WHEEL +4 -0
  51. 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)
@@ -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))