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/cmd/env.py
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"""环境变量操作模块, 提供用户友好的环境变量配置接口."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from ..consts import Constants
|
|
10
|
+
from ..core import logger
|
|
11
|
+
from ..utils.executor import execute
|
|
12
|
+
from ._base import BaseCommand
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class _EnvironmentVar:
|
|
17
|
+
"""环境变量数据类"""
|
|
18
|
+
|
|
19
|
+
name: str
|
|
20
|
+
value: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"ExportEnvCommand",
|
|
25
|
+
"GetEnvCommand",
|
|
26
|
+
"ImportEnvCommand",
|
|
27
|
+
"ListEnvCommand",
|
|
28
|
+
"SetEnvCommand",
|
|
29
|
+
"UnsetEnvCommand",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class GetEnvCommand(BaseCommand):
|
|
34
|
+
"""获取环境变量命令"""
|
|
35
|
+
|
|
36
|
+
name = "getenv"
|
|
37
|
+
description = "获取环境变量值"
|
|
38
|
+
|
|
39
|
+
def __init__(self, name: str, default: str | None = None) -> None:
|
|
40
|
+
super().__init__()
|
|
41
|
+
self.name_val: str = name
|
|
42
|
+
self.default: str | None = default
|
|
43
|
+
self.value: str | None = None
|
|
44
|
+
|
|
45
|
+
def run(self) -> bool:
|
|
46
|
+
"""获取环境变量值"""
|
|
47
|
+
self.value = os.environ.get(self.name_val, self.default)
|
|
48
|
+
if self.value is not None:
|
|
49
|
+
logger.info(f"环境变量 {self.name_val}={self.value}")
|
|
50
|
+
else:
|
|
51
|
+
logger.warning(f"环境变量 {self.name_val} 未设置")
|
|
52
|
+
return self.value is not None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class UnsetEnvCommand(BaseCommand):
|
|
56
|
+
"""删除环境变量命令"""
|
|
57
|
+
|
|
58
|
+
name = "unsetenv"
|
|
59
|
+
description = "删除环境变量"
|
|
60
|
+
|
|
61
|
+
def __init__(self, name: str) -> None:
|
|
62
|
+
super().__init__()
|
|
63
|
+
self.name = name
|
|
64
|
+
|
|
65
|
+
def run(self) -> bool:
|
|
66
|
+
"""删除环境变量"""
|
|
67
|
+
if self.name in os.environ:
|
|
68
|
+
del os.environ[self.name]
|
|
69
|
+
logger.info(f"已删除环境变量: {self.name}")
|
|
70
|
+
return True
|
|
71
|
+
else:
|
|
72
|
+
logger.warning(f"环境变量 {self.name} 不存在")
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ListEnvCommand(BaseCommand):
|
|
77
|
+
"""列出环境变量命令"""
|
|
78
|
+
|
|
79
|
+
name = "listenv"
|
|
80
|
+
description = "列出环境变量"
|
|
81
|
+
|
|
82
|
+
def __init__(self, pattern: str | None = None) -> None:
|
|
83
|
+
super().__init__()
|
|
84
|
+
self.pattern: str | None = pattern
|
|
85
|
+
self.envs: dict[str, str] = {}
|
|
86
|
+
|
|
87
|
+
def run(self) -> bool:
|
|
88
|
+
"""列出环境变量"""
|
|
89
|
+
self.envs = dict(os.environ)
|
|
90
|
+
if self.pattern:
|
|
91
|
+
self.envs = {
|
|
92
|
+
k: v for k, v in self.envs.items() if self.pattern.lower() in k.lower()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if self.envs:
|
|
96
|
+
logger.info(f"找到 {len(self.envs)} 个环境变量")
|
|
97
|
+
for key, value in self.envs.items():
|
|
98
|
+
logger.info(f" {key}={value}")
|
|
99
|
+
else:
|
|
100
|
+
logger.warning("未找到匹配的环境变量")
|
|
101
|
+
return len(self.envs) > 0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class ExportEnvCommand(BaseCommand):
|
|
105
|
+
"""导出环境变量命令"""
|
|
106
|
+
|
|
107
|
+
name = "exportenv"
|
|
108
|
+
description = "导出环境变量到文件"
|
|
109
|
+
|
|
110
|
+
def __init__(self, filepath: str, shell_type: str = "bash") -> None:
|
|
111
|
+
super().__init__()
|
|
112
|
+
self.filepath: str = filepath
|
|
113
|
+
self.shell_type: str = shell_type
|
|
114
|
+
|
|
115
|
+
def run(self) -> bool:
|
|
116
|
+
"""导出环境变量到文件"""
|
|
117
|
+
|
|
118
|
+
from bitool.cmd.io import WriteFileCommand
|
|
119
|
+
|
|
120
|
+
# 生成环境变量脚本内容
|
|
121
|
+
filepath_path = Path(self.filepath)
|
|
122
|
+
lines: list[str] = []
|
|
123
|
+
if self.shell_type == "cmd":
|
|
124
|
+
lines.append("@echo off")
|
|
125
|
+
lines.append(":: 环境变量配置脚本")
|
|
126
|
+
for key, value in os.environ.items():
|
|
127
|
+
lines.append(f"set {key}={value}")
|
|
128
|
+
elif self.shell_type == "powershell":
|
|
129
|
+
lines.append("# 环境变量配置脚本 (PowerShell)")
|
|
130
|
+
for key, value in os.environ.items():
|
|
131
|
+
lines.append(f'$env:{key}="{value}"')
|
|
132
|
+
else: # bash/sh 脚本
|
|
133
|
+
lines.append("#!/bin/bash")
|
|
134
|
+
lines.append("# 环境变量配置脚本")
|
|
135
|
+
for key, value in os.environ.items():
|
|
136
|
+
lines.append(f'export {key}="{value}"')
|
|
137
|
+
|
|
138
|
+
content = "\n".join(lines) + "\n"
|
|
139
|
+
|
|
140
|
+
# 使用 WriteFileCommand 写入文件
|
|
141
|
+
write_cmd = WriteFileCommand(
|
|
142
|
+
filepath=filepath_path, content=content, overwrite=True, backup=False
|
|
143
|
+
)
|
|
144
|
+
return write_cmd.run()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ImportEnvCommand(BaseCommand):
|
|
148
|
+
"""导入环境变量命令"""
|
|
149
|
+
|
|
150
|
+
name = "importenv"
|
|
151
|
+
description = "从文件导入环境变量"
|
|
152
|
+
|
|
153
|
+
def __init__(self, filepath: str) -> None:
|
|
154
|
+
super().__init__()
|
|
155
|
+
self.filepath: str = filepath
|
|
156
|
+
self.count: int = 0
|
|
157
|
+
|
|
158
|
+
def run(self) -> bool:
|
|
159
|
+
"""从文件导入环境变量"""
|
|
160
|
+
filepath_path = Path(self.filepath)
|
|
161
|
+
if not filepath_path.exists():
|
|
162
|
+
logger.error(f"文件不存在: {self.filepath}")
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
count = 0
|
|
167
|
+
with filepath_path.open("r", encoding="utf-8") as f:
|
|
168
|
+
for line in f:
|
|
169
|
+
line = line.strip()
|
|
170
|
+
# 跳过注释和空行
|
|
171
|
+
if not line or line.startswith("#") or line.startswith("@"):
|
|
172
|
+
continue
|
|
173
|
+
|
|
174
|
+
# 解析 export VAR=value (bash)
|
|
175
|
+
if line.startswith("export "):
|
|
176
|
+
line = line[7:] # 移除 "export "
|
|
177
|
+
if "=" in line:
|
|
178
|
+
key, value = line.split("=", 1)
|
|
179
|
+
# 移除引号
|
|
180
|
+
value = value.strip("'\"")
|
|
181
|
+
os.environ[key] = value
|
|
182
|
+
count += 1
|
|
183
|
+
|
|
184
|
+
# 解析 set VAR=value (cmd)
|
|
185
|
+
elif line.startswith("set "):
|
|
186
|
+
line = line[4:] # 移除 "set "
|
|
187
|
+
if "=" in line:
|
|
188
|
+
key, value = line.split("=", 1)
|
|
189
|
+
os.environ[key] = value
|
|
190
|
+
count += 1
|
|
191
|
+
|
|
192
|
+
# 解析 $env:VAR="value" (powershell)
|
|
193
|
+
elif line.startswith("$env:"):
|
|
194
|
+
line = line[5:] # 移除 "$env:"
|
|
195
|
+
if "=" in line:
|
|
196
|
+
key, value = line.split("=", 1)
|
|
197
|
+
# 移除引号
|
|
198
|
+
value = value.strip("'\"")
|
|
199
|
+
os.environ[key] = value
|
|
200
|
+
count += 1
|
|
201
|
+
|
|
202
|
+
self.count = count
|
|
203
|
+
logger.info(f"从文件导入了 {count} 个环境变量: {self.filepath}")
|
|
204
|
+
except Exception as e: # noqa: BLE001
|
|
205
|
+
logger.error(f"导入环境变量失败: {e}")
|
|
206
|
+
return False
|
|
207
|
+
else:
|
|
208
|
+
return count > 0
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class SetEnvCommand(BaseCommand):
|
|
212
|
+
"""设置环境变量命令"""
|
|
213
|
+
|
|
214
|
+
name = "setenv"
|
|
215
|
+
description = "设置环境变量"
|
|
216
|
+
|
|
217
|
+
def __init__(self, envs: list[tuple[str, str]]) -> None:
|
|
218
|
+
super().__init__()
|
|
219
|
+
|
|
220
|
+
self.envs: list[_EnvironmentVar] = [
|
|
221
|
+
_EnvironmentVar(name, value) for name, value in envs
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
def run(self) -> bool:
|
|
225
|
+
"""设置环境变量"""
|
|
226
|
+
if not self.envs:
|
|
227
|
+
logger.warning("未提供环境变量对")
|
|
228
|
+
return False
|
|
229
|
+
|
|
230
|
+
if Constants.IS_WINDOWS:
|
|
231
|
+
for env_var in self.envs:
|
|
232
|
+
execute(["setx", env_var.name, env_var.value])
|
|
233
|
+
else:
|
|
234
|
+
bashrc_path = os.path.expanduser("~/.bashrc")
|
|
235
|
+
# 读取现有的 bashrc 内容
|
|
236
|
+
existing_lines = []
|
|
237
|
+
if os.path.exists(bashrc_path):
|
|
238
|
+
with open(bashrc_path, encoding="utf-8") as f:
|
|
239
|
+
existing_lines = f.readlines()
|
|
240
|
+
|
|
241
|
+
# 追踪需要更新的环境变量
|
|
242
|
+
env_names = {env_var.name for env_var in self.envs}
|
|
243
|
+
|
|
244
|
+
# 过滤掉已存在的环境变量行,并构建新的内容
|
|
245
|
+
new_lines = []
|
|
246
|
+
for line in existing_lines:
|
|
247
|
+
# 检查是否是 export 语句且匹配我们要设置的环境变量
|
|
248
|
+
if line.strip().startswith("export "):
|
|
249
|
+
# 提取变量名
|
|
250
|
+
export_part = line.strip()[7:] # 去掉 "export "
|
|
251
|
+
if "=" in export_part:
|
|
252
|
+
var_name = export_part.split("=", 1)[0]
|
|
253
|
+
if var_name not in env_names:
|
|
254
|
+
new_lines.append(line)
|
|
255
|
+
else:
|
|
256
|
+
new_lines.append(line)
|
|
257
|
+
else:
|
|
258
|
+
new_lines.append(line)
|
|
259
|
+
|
|
260
|
+
# 添加新的环境变量配置
|
|
261
|
+
new_lines.extend(
|
|
262
|
+
f"export {env_var.name}={env_var.value}\n" for env_var in self.envs
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# 写回 bashrc 文件
|
|
266
|
+
with open(bashrc_path, "w", encoding="utf-8") as f:
|
|
267
|
+
f.writelines(new_lines)
|
|
268
|
+
|
|
269
|
+
return True
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class EnvOps:
|
|
273
|
+
"""环境变量操作类
|
|
274
|
+
|
|
275
|
+
提供环境变量的查看、设置、删除、导入/导出等功能
|
|
276
|
+
"""
|
|
277
|
+
|
|
278
|
+
def __init__(self) -> None:
|
|
279
|
+
"""初始化环境变量操作实例"""
|
|
280
|
+
self._envs: dict[str, str] = {}
|
|
281
|
+
|
|
282
|
+
def get(self, name: str, default: str | None = None) -> str | None:
|
|
283
|
+
"""获取环境变量值
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
name: 环境变量名称
|
|
287
|
+
default: 默认值
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
环境变量值或默认值
|
|
291
|
+
"""
|
|
292
|
+
return os.environ.get(name, default)
|
|
293
|
+
|
|
294
|
+
def set(self, name: str, value: str, *, persistent: bool = False) -> None:
|
|
295
|
+
"""设置环境变量
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
name: 环境变量名称
|
|
299
|
+
value: 环境变量值
|
|
300
|
+
persistent: 是否保存到内部配置(用于后续恢复)
|
|
301
|
+
"""
|
|
302
|
+
os.environ[name] = value
|
|
303
|
+
logger.info(f"已设置环境变量: {name}={value}")
|
|
304
|
+
|
|
305
|
+
if persistent:
|
|
306
|
+
self._envs[name] = value
|
|
307
|
+
logger.info(f"已保存环境变量到配置: {name}")
|
|
308
|
+
|
|
309
|
+
def unset(self, name: str, *, remove_persistent: bool = False) -> None:
|
|
310
|
+
"""删除环境变量
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
name: 环境变量名称
|
|
314
|
+
remove_persistent: 是否同时从内部配置中删除
|
|
315
|
+
"""
|
|
316
|
+
if name in os.environ:
|
|
317
|
+
del os.environ[name]
|
|
318
|
+
logger.info(f"已删除环境变量: {name}")
|
|
319
|
+
|
|
320
|
+
if remove_persistent and name in self._envs:
|
|
321
|
+
del self._envs[name]
|
|
322
|
+
logger.info(f"已从配置中删除: {name}")
|
|
323
|
+
|
|
324
|
+
def list_env(self, pattern: str | None = None) -> dict[str, str]:
|
|
325
|
+
"""列出当前环境变量
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
pattern: 可选的过滤模式,只返回包含该模式的变量
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
环境变量字典
|
|
332
|
+
"""
|
|
333
|
+
envs = dict(os.environ)
|
|
334
|
+
if pattern:
|
|
335
|
+
envs = {k: v for k, v in envs.items() if pattern.lower() in k.lower()}
|
|
336
|
+
return envs
|
|
337
|
+
|
|
338
|
+
def show_config(self) -> dict[str, str]:
|
|
339
|
+
"""显示持久化的环境变量配置
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
持久化的环境变量字典
|
|
343
|
+
"""
|
|
344
|
+
return self._envs.copy()
|
|
345
|
+
|
|
346
|
+
def restore(self) -> dict[str, str]:
|
|
347
|
+
"""恢复持久化的环境变量
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
已恢复的环境变量字典
|
|
351
|
+
"""
|
|
352
|
+
restored = {}
|
|
353
|
+
for key, value in self._envs.items():
|
|
354
|
+
os.environ[key] = value
|
|
355
|
+
restored[key] = value
|
|
356
|
+
logger.info(f"已恢复环境变量: {key}={value}")
|
|
357
|
+
return restored
|
|
358
|
+
|
|
359
|
+
def clear_all(self) -> None:
|
|
360
|
+
"""清除所有配置的环境变量"""
|
|
361
|
+
for key in list(self._envs.keys()):
|
|
362
|
+
if key in os.environ:
|
|
363
|
+
del os.environ[key]
|
|
364
|
+
logger.info(f"已删除环境变量: {key}")
|
|
365
|
+
|
|
366
|
+
self._envs.clear()
|
|
367
|
+
logger.info("已清除所有环境变量配置")
|
|
368
|
+
|
|
369
|
+
def export_to_file(self, filepath: str, *, shell_type: str = "bash") -> None:
|
|
370
|
+
"""导出环境变量到脚本文件
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
filepath: 输出文件路径
|
|
374
|
+
shell_type: 脚本类型 (bash/cmd/powershell),默认"bash"
|
|
375
|
+
"""
|
|
376
|
+
filepath_path = Path(filepath)
|
|
377
|
+
filepath_path.parent.mkdir(parents=True, exist_ok=True)
|
|
378
|
+
|
|
379
|
+
lines = []
|
|
380
|
+
if shell_type == "cmd":
|
|
381
|
+
lines.append("@echo off")
|
|
382
|
+
lines.append(":: 环境变量配置脚本")
|
|
383
|
+
for key, value in self._envs.items():
|
|
384
|
+
lines.append(f"set {key}={value}")
|
|
385
|
+
elif shell_type == "powershell":
|
|
386
|
+
lines.append("# 环境变量配置脚本 (PowerShell)")
|
|
387
|
+
for key, value in self._envs.items():
|
|
388
|
+
lines.append(f'$env:{key}="{value}"')
|
|
389
|
+
else: # bash/sh 脚本
|
|
390
|
+
lines.append("#!/bin/bash")
|
|
391
|
+
lines.append("# 环境变量配置脚本")
|
|
392
|
+
for key, value in self._envs.items():
|
|
393
|
+
lines.append(f'export {key}="{value}"')
|
|
394
|
+
|
|
395
|
+
content = "\n".join(lines) + "\n"
|
|
396
|
+
with filepath_path.open("w", encoding="utf-8") as f:
|
|
397
|
+
f.write(content)
|
|
398
|
+
logger.info(f"已导出环境变量到: {filepath}")
|
|
399
|
+
|
|
400
|
+
def import_from_file(self, filepath: str) -> int:
|
|
401
|
+
"""从脚本文件导入环境变量
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
filepath: 导入文件路径
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
成功导入的环境变量数量
|
|
408
|
+
"""
|
|
409
|
+
filepath_path = Path(filepath)
|
|
410
|
+
if not filepath_path.exists():
|
|
411
|
+
msg = f"文件不存在: {filepath}"
|
|
412
|
+
raise FileNotFoundError(msg)
|
|
413
|
+
|
|
414
|
+
count = 0
|
|
415
|
+
with filepath_path.open("r", encoding="utf-8") as f:
|
|
416
|
+
for line in f:
|
|
417
|
+
line = line.strip()
|
|
418
|
+
# 跳过注释和空行
|
|
419
|
+
if not line or line.startswith("#") or line.startswith("@"):
|
|
420
|
+
continue
|
|
421
|
+
|
|
422
|
+
# 解析 export VAR=value (bash)
|
|
423
|
+
if line.startswith("export "):
|
|
424
|
+
line = line[7:] # 移除 "export "
|
|
425
|
+
if "=" in line:
|
|
426
|
+
key, value = line.split("=", 1)
|
|
427
|
+
# 移除引号
|
|
428
|
+
value = value.strip("'\"")
|
|
429
|
+
self.set(key, value)
|
|
430
|
+
count += 1
|
|
431
|
+
|
|
432
|
+
# 解析 set VAR=value (cmd)
|
|
433
|
+
elif line.startswith("set "):
|
|
434
|
+
line = line[4:] # 移除 "set "
|
|
435
|
+
if "=" in line:
|
|
436
|
+
key, value = line.split("=", 1)
|
|
437
|
+
self.set(key, value)
|
|
438
|
+
count += 1
|
|
439
|
+
|
|
440
|
+
# 解析 $env:VAR="value" (powershell)
|
|
441
|
+
elif line.startswith("$env:"):
|
|
442
|
+
line = line[5:] # 移除 "$env:"
|
|
443
|
+
if "=" in line:
|
|
444
|
+
key, value = line.split("=", 1)
|
|
445
|
+
# 移除引号
|
|
446
|
+
value = value.strip("'\"")
|
|
447
|
+
self.set(key, value)
|
|
448
|
+
count += 1
|
|
449
|
+
|
|
450
|
+
logger.info(f"从文件导入了 {count} 个环境变量: {filepath}")
|
|
451
|
+
return count
|
|
452
|
+
|
|
453
|
+
def __repr__(self) -> str:
|
|
454
|
+
return "EnvOps(环境变量配置工具)"
|
bitool/cmd/git.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Git命令封装模块.
|
|
2
|
+
|
|
3
|
+
提供常用的Git操作命令封装, 包括提交、标签、检测等功能.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from bitool.cmd._base import BaseCommand
|
|
12
|
+
from bitool.cmd._condition import BuiltinConditions
|
|
13
|
+
from bitool.cmd.run import RunCommand
|
|
14
|
+
from bitool.core import logger
|
|
15
|
+
from bitool.utils import execute
|
|
16
|
+
|
|
17
|
+
# Git 条件检查
|
|
18
|
+
_GIT_INSTALLED = BuiltinConditions.HAS_APP_INSTALLED("git")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _is_git_repo() -> bool:
|
|
22
|
+
"""检查当前目录是否为 Git 仓库.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
bool
|
|
27
|
+
如果是 Git 仓库返回 True, 否则返回 False
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
execute(["git", "rev-parse", "--git-dir"], check=True, capture_output=True)
|
|
31
|
+
except (FileNotFoundError, OSError, RuntimeError):
|
|
32
|
+
return False
|
|
33
|
+
else:
|
|
34
|
+
return True
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class GitAddCommand(RunCommand):
|
|
39
|
+
"""Git add 命令.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
files: 要添加的文件列表, 默认 None
|
|
43
|
+
all_files: 是否添加所有文件, 默认 False
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
name: str = "git-add"
|
|
47
|
+
description: str = "添加文件到 Git 暂存区"
|
|
48
|
+
files: list[Path] | None = None
|
|
49
|
+
all_files: bool = False
|
|
50
|
+
allow_conditions: list = field(default_factory=lambda: [_GIT_INSTALLED])
|
|
51
|
+
|
|
52
|
+
def __post_init__(self) -> None:
|
|
53
|
+
"""数据类初始化后的处理, 构建 cmd 列表."""
|
|
54
|
+
if self.all_files:
|
|
55
|
+
self.cmd = ["git", "add", "."]
|
|
56
|
+
elif self.files:
|
|
57
|
+
self.cmd = ["git", "add"] + [str(f) for f in self.files]
|
|
58
|
+
else:
|
|
59
|
+
self.cmd = ["git", "add", "."]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class GitCommitCommand(RunCommand):
|
|
64
|
+
"""Git commit 命令.
|
|
65
|
+
|
|
66
|
+
Attributes:
|
|
67
|
+
message: 提交消息, 默认 "chore: update"
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
name: str = "git-commit"
|
|
71
|
+
description: str = "提交 Git 更改"
|
|
72
|
+
message: str = "chore: update"
|
|
73
|
+
allow_conditions: list = field(default_factory=lambda: [_GIT_INSTALLED])
|
|
74
|
+
|
|
75
|
+
def __post_init__(self) -> None:
|
|
76
|
+
"""数据类初始化后的处理, 构建 cmd 列表."""
|
|
77
|
+
self.cmd = ["git", "commit", "-m", self.message]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class GitTagCommand(RunCommand):
|
|
82
|
+
"""Git tag 命令.
|
|
83
|
+
|
|
84
|
+
Attributes:
|
|
85
|
+
tag_name: 标签名称
|
|
86
|
+
message: 标签消息, 默认 None (创建轻量标签)
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
name: str = "git-tag"
|
|
90
|
+
description: str = "创建 Git 标签"
|
|
91
|
+
tag_name: str = ""
|
|
92
|
+
message: str | None = None
|
|
93
|
+
allow_conditions: list = field(default_factory=lambda: [_GIT_INSTALLED])
|
|
94
|
+
|
|
95
|
+
def __post_init__(self) -> None:
|
|
96
|
+
"""数据类初始化后的处理, 构建 cmd 列表."""
|
|
97
|
+
if self.message:
|
|
98
|
+
self.cmd = ["git", "tag", "-a", self.tag_name, "-m", self.message]
|
|
99
|
+
else:
|
|
100
|
+
self.cmd = ["git", "tag", self.tag_name]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class GitCheckIsRepoCommand(BaseCommand):
|
|
105
|
+
"""检查是否为 Git 仓库的命令."""
|
|
106
|
+
|
|
107
|
+
name: str = "git-is-repo"
|
|
108
|
+
description: str = "检查当前目录是否为 Git 仓库"
|
|
109
|
+
|
|
110
|
+
def run(self) -> bool:
|
|
111
|
+
"""执行检查.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
bool
|
|
116
|
+
如果是 Git 仓库返回 True
|
|
117
|
+
"""
|
|
118
|
+
is_repo = _is_git_repo()
|
|
119
|
+
if is_repo:
|
|
120
|
+
logger.info("当前目录是 Git 仓库")
|
|
121
|
+
else:
|
|
122
|
+
logger.warning("当前目录不是 Git 仓库")
|
|
123
|
+
return is_repo
|