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/cmd/version.py ADDED
@@ -0,0 +1,630 @@
1
+ """版本号管理相关命令.
2
+
3
+ 提供文件和 TOML 文档的版本号读取、更新和递增功能.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import re
9
+ from dataclasses import dataclass, field
10
+ from pathlib import Path
11
+ from typing import ClassVar
12
+
13
+ try:
14
+ import tomli
15
+ import tomli_w
16
+ except ImportError:
17
+ try:
18
+ import tomli_w
19
+ import tomllib as tomli # ty: ignore[unresolved-import]
20
+ except ImportError:
21
+ tomli = None # ty: ignore
22
+ tomli_w = None # ty: ignore
23
+
24
+ from bitool.cmd._base import BaseCommand
25
+ from bitool.core import logger
26
+
27
+
28
+ @dataclass
29
+ class ReadTextVersionCommand(BaseCommand):
30
+ """从文本文件读取版本号命令.
31
+
32
+ 使用正则表达式从文本文件中提取版本号.
33
+
34
+ Attributes:
35
+ filepath: 文件路径
36
+ pattern: 正则表达式模式
37
+ version: 读取到的版本号
38
+ """
39
+
40
+ name: str = "read-text-version"
41
+ description: str = "从文本文件读取版本号"
42
+ filepath: Path = Path()
43
+ pattern: str = ""
44
+ version: str = ""
45
+
46
+ def run(self) -> bool:
47
+ """执行文本文件版本号读取.
48
+
49
+ Returns
50
+ -------
51
+ bool
52
+ 读取成功返回True, 否则返回False
53
+ """
54
+ if not self.filepath.exists():
55
+ logger.warning(f"文件不存在: {self.filepath}")
56
+ return False
57
+
58
+ if not self.pattern:
59
+ logger.error("未提供正则表达式模式")
60
+ return False
61
+
62
+ try:
63
+ content = self.filepath.read_text(encoding="utf-8")
64
+ match = re.search(self.pattern, content, re.MULTILINE)
65
+ if not match:
66
+ logger.warning(f"在 {self.filepath} 中未找到版本号")
67
+ return False
68
+
69
+ self.version = match.group(1)
70
+ logger.info(f"读取到版本号: {self.filepath} -> {self.version}")
71
+ except Exception as e: # noqa: BLE001
72
+ logger.error(f"读取文本版本号失败: {e}")
73
+ return False
74
+ else:
75
+ return True
76
+
77
+
78
+ @dataclass
79
+ class UpdateTextVersionCommand(BaseCommand):
80
+ """更新文本文件版本号命令.
81
+
82
+ 使用正则表达式替换文本文件中的版本号.
83
+
84
+ Attributes:
85
+ filepath: 文件路径
86
+ pattern: 查找正则表达式模式
87
+ template: 替换模板字符串 (使用 {} 占位新版本号)
88
+ version: 新版本号
89
+ """
90
+
91
+ name: str = "update-text-version"
92
+ description: str = "更新文本文件中的版本号"
93
+ filepath: Path = Path()
94
+ pattern: str = ""
95
+ template: str = ""
96
+ version: str = ""
97
+
98
+ def run(self) -> bool:
99
+ """执行文本文件版本号更新.
100
+
101
+ Returns
102
+ -------
103
+ bool
104
+ 更新成功返回True, 否则返回False
105
+ """
106
+ if not self.filepath.parent.exists():
107
+ logger.warning(f"目录不存在: {self.filepath.parent}")
108
+ return False
109
+
110
+ if not self.pattern or not self.template:
111
+ logger.error("未提供正则表达式模式或替换模板")
112
+ return False
113
+
114
+ try:
115
+ content = self.filepath.read_text(encoding="utf-8")
116
+ new_content = re.sub(
117
+ self.pattern,
118
+ self.template.format(self.version),
119
+ content,
120
+ flags=re.MULTILINE,
121
+ )
122
+ self.filepath.write_text(new_content, encoding="utf-8")
123
+ logger.info(f"已更新版本号: {self.filepath} -> {self.version}")
124
+ except Exception as e: # noqa: BLE001
125
+ logger.error(f"更新文本版本号失败: {e}")
126
+ return False
127
+ else:
128
+ return True
129
+
130
+
131
+ @dataclass
132
+ class BumpFileVersionCommand(BaseCommand):
133
+ """文件版本号递增命令.
134
+
135
+ 读取文件当前版本号, 递增指定部分, 然后更新文件.
136
+
137
+ Attributes:
138
+ filepath: 文件路径
139
+ version_part: 版本号部分 (major, minor, patch)
140
+ prerelease: 可选的预发布标识
141
+ read_pattern: 读取版本号的正则表达式 (文本文件用)
142
+ update_template: 更新版本号的模板 (文本文件用)
143
+ version_path: 版本号在TOML中的路径 (TOML文件用)
144
+ old_version: 原版本号
145
+ new_version: 新版本号
146
+ """
147
+
148
+ name: str = "bump-file-version"
149
+ description: str = "递增文件中的版本号"
150
+ filepath: Path = Path()
151
+ version_part: str = "patch"
152
+ prerelease: str | None = None
153
+ read_pattern: str = ""
154
+ update_template: str = ""
155
+ version_path: list[str] = field(default_factory=lambda: ["project", "version"])
156
+ old_version: str = ""
157
+ new_version: str = ""
158
+
159
+ def run(self) -> bool:
160
+ """执行文件版本号递增.
161
+
162
+ Returns
163
+ -------
164
+ bool
165
+ 递增成功返回True, 否则返回False
166
+ """
167
+ if not self.filepath.exists():
168
+ logger.warning(f"文件不存在: {self.filepath}")
169
+ return False
170
+
171
+ try:
172
+ # 读取当前版本号
173
+ current_version = self._read_version()
174
+ if not current_version:
175
+ return False
176
+
177
+ self.old_version = current_version
178
+
179
+ # 递增版本号
180
+ bumped_version = self._bump_version(current_version)
181
+ if not bumped_version:
182
+ return False
183
+
184
+ self.new_version = bumped_version
185
+
186
+ # 更新文件
187
+ if not self._update_version(bumped_version):
188
+ return False
189
+
190
+ logger.info(
191
+ f"已更新版本号: {self.filepath} ({self.old_version} -> {self.new_version})"
192
+ )
193
+ except Exception as e: # noqa: BLE001
194
+ logger.error(f"递增文件版本号失败: {e}")
195
+ return False
196
+ else:
197
+ return True
198
+
199
+ def _read_version(self) -> str | None:
200
+ """读取当前版本号.
201
+
202
+ Returns
203
+ -------
204
+ str | None
205
+ 当前版本号, 失败时返回None
206
+ """
207
+ # 判断文件类型 (Cargo.toml 使用文本方式处理)
208
+ if self.filepath.suffix == ".toml" and self.filepath.name != "Cargo.toml":
209
+ return self._read_toml_version()
210
+ else:
211
+ return self._read_text_version()
212
+
213
+ def _read_toml_version(self) -> str | None:
214
+ """从TOML文件读取版本号.
215
+
216
+ Returns
217
+ -------
218
+ str | None
219
+ 版本号, 失败时返回None
220
+ """
221
+ if tomli is None:
222
+ logger.error("未安装tomli或tomllib库")
223
+ return None
224
+
225
+ try:
226
+ with self.filepath.open("rb") as f:
227
+ data = tomli.load(f)
228
+
229
+ current = data
230
+ for key in self.version_path:
231
+ if key not in current:
232
+ logger.warning(
233
+ f"在 {self.filepath} 中未找到版本号路径: {'.'.join(self.version_path)}"
234
+ )
235
+ return None
236
+ current = current[key]
237
+
238
+ return str(current)
239
+ except Exception as e: # noqa: BLE001
240
+ logger.error(f"读取TOML版本号失败: {e}")
241
+ return None
242
+
243
+ def _read_text_version(self) -> str | None:
244
+ """从文本文件读取版本号.
245
+
246
+ Returns
247
+ -------
248
+ str | None
249
+ 版本号, 失败时返回None
250
+ """
251
+ if not self.read_pattern:
252
+ logger.error("未提供读取版本号的正则表达式")
253
+ return None
254
+
255
+ try:
256
+ content = self.filepath.read_text(encoding="utf-8")
257
+ match = re.search(self.read_pattern, content, re.MULTILINE)
258
+ if not match:
259
+ logger.warning(f"在 {self.filepath} 中未找到版本号")
260
+ return None
261
+
262
+ return match.group(1)
263
+ except Exception as e: # noqa: BLE001
264
+ logger.error(f"读取文本版本号失败: {e}")
265
+ return None
266
+
267
+ def _bump_version(self, version_str: str) -> str | None:
268
+ """递增版本号.
269
+
270
+ Parameters
271
+ ----------
272
+ version_str : str
273
+ 当前版本号字符串
274
+
275
+ Returns
276
+ -------
277
+ str | None
278
+ 递增后的版本号, 失败时返回None
279
+ """
280
+ try:
281
+ # 解析版本号
282
+ version_pattern = re.compile(
283
+ r"(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)"
284
+ r"(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?"
285
+ r"(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?"
286
+ )
287
+ match = version_pattern.match(version_str)
288
+ if not match:
289
+ logger.error(f"无效的版本号格式: {version_str}")
290
+ return None
291
+
292
+ major = int(match.group("major"))
293
+ minor = int(match.group("minor"))
294
+ patch = int(match.group("patch"))
295
+
296
+ # 递增指定部分
297
+ if self.version_part == "major":
298
+ major += 1
299
+ minor = 0
300
+ patch = 0
301
+ prerelease = None
302
+ elif self.version_part == "minor":
303
+ minor += 1
304
+ patch = 0
305
+ prerelease = None
306
+ elif self.version_part == "patch":
307
+ patch += 1
308
+ prerelease = None
309
+ else:
310
+ logger.error(f"不支持的版本号部分: {self.version_part}")
311
+ return None
312
+
313
+ # 设置预发布标识
314
+ if self.prerelease:
315
+ prerelease: str = self.prerelease
316
+
317
+ # 构建新版本号
318
+ new_version = f"{major}.{minor}.{patch}"
319
+ if prerelease:
320
+ new_version += f"-{prerelease}"
321
+ except Exception as e: # noqa: BLE001
322
+ logger.error(f"递增版本号失败: {e}")
323
+ return None
324
+ else:
325
+ return new_version
326
+
327
+ def _update_version(self, new_version: str) -> bool:
328
+ """更新文件中的版本号.
329
+
330
+ Parameters
331
+ ----------
332
+ new_version : str
333
+ 新版本号
334
+
335
+ Returns
336
+ -------
337
+ bool
338
+ 更新成功返回True, 否则返回False
339
+ """
340
+ # 判断文件类型 (Cargo.toml 使用文本方式处理)
341
+ if self.filepath.suffix == ".toml" and self.filepath.name != "Cargo.toml":
342
+ return self._update_toml_version(new_version)
343
+ else:
344
+ return self._update_text_version(new_version)
345
+
346
+ def _update_toml_version(self, new_version: str) -> bool:
347
+ """更新TOML文件中的版本号.
348
+
349
+ 使用文本替换方式, 只更新版本号所在行, 保持其他内容格式不变.
350
+
351
+ Parameters
352
+ ----------
353
+ new_version : str
354
+ 新版本号
355
+
356
+ Returns
357
+ -------
358
+ bool
359
+ 更新成功返回True, 否则返回False
360
+ """
361
+ if tomli is None:
362
+ logger.error("未安装tomli或tomllib库")
363
+ return False
364
+
365
+ try:
366
+ # 先读取并验证版本号路径
367
+ with self.filepath.open("rb") as f:
368
+ data = tomli.load(f)
369
+
370
+ current = data
371
+ for key in self.version_path:
372
+ if key not in current:
373
+ logger.warning(
374
+ f"在 {self.filepath} 中未找到版本号路径: {'.'.join(self.version_path)}"
375
+ )
376
+ return False
377
+ current = current[key]
378
+
379
+ # 使用文本替换方式更新版本号, 保持其他格式不变
380
+ content = self.filepath.read_text(encoding="utf-8")
381
+
382
+ # 构建版本号键名 (例如: project.version -> version)
383
+ version_key = self.version_path[-1]
384
+
385
+ # 匹配版本号行: version = "1.0.0" 或 version = '1.0.0'
386
+ # 支持行首缩进、等号对齐、不同的引号格式
387
+ # (\s*) 捕获行首缩进
388
+ # ({version_key}) 捕获键名
389
+ # (\s*=\s*) 捕获等号及其前后的空格(保持对齐)
390
+ pattern = rf'^(\s*)({version_key})(\s*=\s*)(["\'])([^"\']+)(\4)'
391
+
392
+ def replace_version(match: re.Match) -> str:
393
+ indent = match.group(1) # 行首缩进
394
+ key = match.group(2) # 键名 (version)
395
+ equals_spacing = match.group(3) # 等号及前后空格 ( = )
396
+ quote = match.group(4) # " 或 '
397
+ return f"{indent}{key}{equals_spacing}{quote}{new_version}{quote}"
398
+
399
+ new_content = re.sub(pattern, replace_version, content, flags=re.MULTILINE)
400
+
401
+ if new_content == content:
402
+ logger.warning(f"在 {self.filepath} 中未找到版本号行")
403
+ return False
404
+
405
+ self.filepath.write_text(new_content, encoding="utf-8")
406
+ except Exception as e: # noqa: BLE001
407
+ logger.error(f"更新TOML版本号失败: {e}")
408
+ return False
409
+ else:
410
+ return True
411
+
412
+ def _update_text_version(self, new_version: str) -> bool:
413
+ """更新文本文件中的版本号.
414
+
415
+ Parameters
416
+ ----------
417
+ new_version : str
418
+ 新版本号
419
+
420
+ Returns
421
+ -------
422
+ bool
423
+ 更新成功返回True, 否则返回False
424
+ """
425
+ if not self.read_pattern:
426
+ logger.error("未提供读取模式")
427
+ return False
428
+
429
+ try:
430
+ content = self.filepath.read_text(encoding="utf-8")
431
+
432
+ # 如果提供了 update_template, 使用原有逻辑(向后兼容)
433
+ if self.update_template:
434
+ new_content = re.sub(
435
+ self.read_pattern,
436
+ self.update_template.format(new_version),
437
+ content,
438
+ flags=re.MULTILINE,
439
+ )
440
+ else:
441
+ # 如果没有提供 update_template, 智能替换以保持格式对齐
442
+ # 从 read_pattern 中提取键名(假设是 version)
443
+ # 使用与 _update_toml_version 相同的逻辑保持空格对齐
444
+ # read_pattern 应该是像 ^version\s*=\s*"([^"]+)" 这样的格式
445
+ # 我们需要提取键名
446
+ key_match = re.match(r"^\^?\s*(\w+)", self.read_pattern)
447
+ if not key_match:
448
+ logger.error("无法从读取模式中提取键名")
449
+ return False
450
+
451
+ version_key = key_match.group(1)
452
+ pattern = rf'^(\s*)({version_key})(\s*=\s*)(["\'])([^"\']+)(\4)'
453
+
454
+ def replace_version(match: re.Match) -> str:
455
+ indent = match.group(1) # 行首缩进
456
+ key = match.group(2) # 键名 (version)
457
+ equals_spacing = match.group(3) # 等号及前后空格 ( = )
458
+ quote = match.group(4) # " 或 '
459
+ return f"{indent}{key}{equals_spacing}{quote}{new_version}{quote}"
460
+
461
+ new_content = re.sub(
462
+ pattern, replace_version, content, flags=re.MULTILINE
463
+ )
464
+
465
+ self.filepath.write_text(new_content, encoding="utf-8")
466
+ except Exception as e: # noqa: BLE001
467
+ logger.error(f"更新文本版本号失败: {e}")
468
+ return False
469
+ else:
470
+ return True
471
+
472
+
473
+ @dataclass
474
+ class BumpProjectVersionCommand(BaseCommand):
475
+ """递增项目版本号命令.
476
+
477
+ 查找项目中的所有版本文件 (pyproject.toml, __init__.py 等),
478
+ 并递增它们的版本号.
479
+
480
+ Attributes:
481
+ root_path: 项目根目录路径
482
+ part: 版本号部分 (major, minor, patch)
483
+ prerelease: 可选的预发布标识
484
+ excluded_dirs: 排除的目录名称集合
485
+ exclude_root: 是否排除根目录的 pyproject.toml
486
+ updated_files: 已更新的文件列表
487
+ """
488
+
489
+ name: str = "bump-project-version"
490
+ description: str = "递增项目中所有文件的版本号"
491
+ root_path: Path = field(default_factory=Path.cwd)
492
+ part: str = "patch"
493
+ prerelease: str | None = None
494
+ excluded_dirs: set[str] = field(
495
+ default_factory=lambda: {
496
+ "__pycache__",
497
+ ".venv",
498
+ "venv",
499
+ "env",
500
+ ".git",
501
+ "dist",
502
+ "build",
503
+ ".tox",
504
+ ".pytest_cache",
505
+ }
506
+ )
507
+ exclude_root: bool = False
508
+ updated_files: list[Path] = field(default_factory=list)
509
+
510
+ # 文件类型配置: (文件名, 读取正则, 更新模板)
511
+ FILE_PATTERNS: ClassVar[dict[str, tuple[str, str | None]]] = {
512
+ "__init__.py": (
513
+ r'__version__\s*=\s*["\']([^"\']+)["\']',
514
+ r'__version__ = "{}"',
515
+ ),
516
+ "setup.py": (r'version\s*=\s*["\']([^"\']+)["\']', r'version = "{}"'),
517
+ "package.json": (r'"version"\s*:\s*"([^"]+)"', r'"version": "{}"'),
518
+ # Cargo.toml 不提供 update_template, 使用智能替换保持等号对齐
519
+ "Cargo.toml": (r'^version\s*=\s*"([^"]+)"', None),
520
+ }
521
+
522
+ def run(self) -> bool:
523
+ """执行项目版本号递增.
524
+
525
+ Returns
526
+ -------
527
+ bool
528
+ 递增成功返回True, 否则返回False
529
+ """
530
+ if not self.root_path.exists():
531
+ logger.warning(f"项目目录不存在: {self.root_path}")
532
+ return False
533
+
534
+ try:
535
+ # 查找所有需要更新的版本文件
536
+ version_files = self._find_version_files()
537
+
538
+ if not version_files:
539
+ logger.warning("未找到任何包含版本号的文件")
540
+ return False
541
+
542
+ logger.info(f"找到 {len(version_files)} 个版本文件")
543
+
544
+ # 对每个文件执行版本号递增
545
+ success_count = 0
546
+ for filepath in version_files:
547
+ cmd = self._create_bump_command(filepath)
548
+ if cmd.run():
549
+ self.updated_files.append(filepath)
550
+ success_count += 1
551
+
552
+ logger.info(f"成功更新 {success_count}/{len(version_files)} 个文件")
553
+ except Exception as e: # noqa: BLE001
554
+ logger.error(f"递增项目版本号失败: {e}")
555
+ return False
556
+ else:
557
+ return success_count > 0
558
+
559
+ def _find_version_files(self) -> list[Path]:
560
+ """查找项目中所有包含版本号的文件.
561
+
562
+ Returns
563
+ -------
564
+ list[Path]
565
+ 版本文件路径列表
566
+ """
567
+ version_files: list[Path] = []
568
+
569
+ # 递归遍历目录
570
+ for filepath in self.root_path.rglob("*"):
571
+ # 跳过排除的目录
572
+ if any(excluded in filepath.parts for excluded in self.excluded_dirs):
573
+ continue
574
+
575
+ # 跳过非文件
576
+ if not filepath.is_file():
577
+ continue
578
+
579
+ # 检查是否是 pyproject.toml
580
+ if filepath.name == "pyproject.toml":
581
+ # 如果排除根目录, 跳过根目录的 pyproject.toml
582
+ if self.exclude_root and filepath.parent == self.root_path:
583
+ continue
584
+ version_files.append(filepath)
585
+
586
+ # 检查其他文件类型
587
+ elif filepath.name in self.FILE_PATTERNS:
588
+ version_files.append(filepath)
589
+
590
+ return version_files
591
+
592
+ def _create_bump_command(self, filepath: Path) -> BumpFileVersionCommand:
593
+ """为指定文件创建版本号递增命令.
594
+
595
+ Parameters
596
+ ----------
597
+ filepath : Path
598
+ 文件路径
599
+
600
+ Returns
601
+ -------
602
+ BumpFileVersionCommand
603
+ 配置好的版本号递增命令对象
604
+ """
605
+ # TOML 文件使用 version_path (Cargo.toml 除外)
606
+ if filepath.suffix == ".toml" and filepath.name != "Cargo.toml":
607
+ return BumpFileVersionCommand(
608
+ filepath=filepath,
609
+ version_part=self.part,
610
+ prerelease=self.prerelease,
611
+ version_path=["project", "version"],
612
+ )
613
+
614
+ # 文本文件使用正则表达式
615
+ read_pattern = ""
616
+ update_template: str | None = ""
617
+
618
+ for filename, (pattern, template) in self.FILE_PATTERNS.items():
619
+ if filepath.name == filename:
620
+ read_pattern = pattern
621
+ update_template = template
622
+ break
623
+
624
+ return BumpFileVersionCommand(
625
+ filepath=filepath,
626
+ version_part=self.part,
627
+ prerelease=self.prerelease,
628
+ read_pattern=read_pattern,
629
+ update_template=update_template or "",
630
+ )
bitool/consts.py ADDED
@@ -0,0 +1,14 @@
1
+ import platform
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass(frozen=True)
6
+ class Constants:
7
+ IS_WINDOWS = platform.system() == "Windows"
8
+ IS_UNIX = platform.system() == "Linux" or platform.system() == "Darwin"
9
+ IS_CYGWIN = platform.system() == "CYGWIN"
10
+ IS_MINGW = platform.system() == "MINGW"
11
+ IS_WSL = platform.system() == "Linux" and "microsoft" in platform.release().lower()
12
+ IS_MSYS = platform.system() == "MSYS"
13
+
14
+ EXTENSION = ".exe" if IS_WINDOWS else ""
@@ -0,0 +1,7 @@
1
+ """核心业务逻辑模块."""
2
+
3
+ from .config import ConfigMixin
4
+ from .env import env_check_enabled
5
+ from .logger import logger
6
+
7
+ __all__ = ["ConfigMixin", "env_check_enabled", "logger"]