Skip to content

Commit 0b5e741

Browse files
committed
[工具集更新]:新增 CMake 格式化工具并移除 Syncthing 监控工具
- 新增:添加 `format_cmake` 工具,支持单个文件或递归目录的 CMake 文件格式化,支持多线程并行处理 - 移除:删除 `syncthing_monitor` 工具及相关文件,因项目需求调整 - 依赖:在 `pyproject.toml` 中添加 `cmake_format` 依赖包 - 文档:更新 README.md 工具列表,反映新增和移除的工具项 - 优化:增强 `format_cmake` 工具的跨平台兼容性,支持虚拟环境、Homebrew 等多种安装方式
1 parent e7d9fe6 commit 0b5e741

File tree

4 files changed

+166
-172
lines changed

4 files changed

+166
-172
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
|---|---|---|
1212
| **cli_logger** | loguru 日志配置示例,控制台 + 文件双通道输出 | [`cli_logger.py`](cli_logger/cli_logger.py) |
1313
| **dirwatch** | 实时监控文件夹变化(增/删/改/重命名) | [`dirwatch.py`](dirwatch/dirwatch.py) |
14+
| **format_cmake** | 格式化 CMake 文件(单个或递归目录) | [`format_cmake.py`](format_cmake/format_cmake.py) |
1415
| **hash** | 计算文件或文本的哈希值(MD5/SHA-1/SHA-2/SHA-3/BLAKE2/BLAKE3) | [`hash.py`](hash/hash.py) |
1516
| **image-toolkit** | 图片格式转换工具 + 一键生成/解析`.icns` / `.ico` | [`convert_img.py`](image-toolkit/convert_img.py) / [`dump_icns.py`](image-toolkit/dump_icns.py) / [`dump_ico.py`](image-toolkit/dump_ico.py) / [`make_icns.py`](image-toolkit/make_icns.py) / [`make_ico.py`](image-toolkit/make_ico.py) |
1617
| **m3u8_download** | m3u8 下载器,自动合并 ts 为单个视频 | [`m3u8_dl.py`](m3u8_download/m3u8_dl.py) |
1718
| **procmon** | 按进程名实时监控 CPU/内存/线程/句柄 | [`procmon.py`](procmon/procmon.py) |
1819
| **resolve** | 域名解析工具,快速获取 IP、端口、协议信息 | [`resolve.py`](resolve/resolve.py) |
19-
| **syncthing** | Syncthing API 封装,监控文件夹与设备状态 | [`syncthing_monitor.py`](syncthing/syncthing_monitor.py) |
2020
| **tree** | 可视化目录树生成工具 | [`tree.py`](tree/tree.py) |
2121
| **utils** | 通用工具库(颜色输出等) | [`colors.py`](utils/colors.py) |
2222
| **sync_req** | 依赖同步工具,从 pyproject.toml 生成 requirements.txt | [`sync_req.py`](sync_req.py) |

format_cmake/format_cmake.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
format_cmake.py —— 立即格式化单个 .cmake 文件,或递归格式化目录下所有 .cmake 文件。
4+
5+
用法:
6+
python format_cmake.py file.cmake # 格式化单个文件
7+
python format_cmake.py dir # 递归格式化目录下所有 *.cmake
8+
python format_cmake.py dir -j 8 # 指定 8 线程并行
9+
python format_cmake.py -h
10+
"""
11+
12+
from __future__ import annotations
13+
import argparse
14+
import os
15+
import shutil
16+
import subprocess
17+
import sys
18+
from pathlib import Path
19+
from concurrent.futures import ThreadPoolExecutor
20+
from typing import Iterable, List
21+
from utils import Colors
22+
23+
24+
def _all_site_script_dirs() -> List[Path]:
25+
dirs: List[Path] = []
26+
exe_name = "cmake-format.exe" if sys.platform == "win32" else "cmake-format"
27+
28+
# 1. 当前虚拟环境(最优先)
29+
if hasattr(sys, "real_prefix") or (
30+
hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
31+
):
32+
venv_scripts = Path(sys.prefix) / (
33+
"Scripts" if sys.platform == "win32" else "bin"
34+
)
35+
dirs.append(venv_scripts)
36+
37+
# 2. Windows 用户目录下的 PythonXX\Scripts
38+
if sys.platform == "win32":
39+
roaming = Path.home() / "AppData" / "Roaming" / "Python"
40+
for ver_dir in roaming.glob("Python*"):
41+
dirs.append(ver_dir / "Scripts")
42+
43+
# 3. 当前 Python 环境的 Scripts/bin
44+
dirs.append(Path(sys.prefix) / ("Scripts" if sys.platform == "win32" else "bin"))
45+
46+
# 4. pip show 给出的 location(cmake-format 官方 wheel 会放 data/)
47+
try:
48+
loc = subprocess.check_output(
49+
[sys.executable, "-m", "pip", "show", "cmake-format"],
50+
stderr=subprocess.DEVNULL,
51+
text=True,
52+
).splitlines()
53+
for line in loc:
54+
if line.startswith("Location:"):
55+
data_dir = Path(line.split(":", 1)[1].strip()) / "cmake_format" / "data"
56+
dirs.append(data_dir)
57+
break
58+
except Exception:
59+
pass
60+
61+
# 5. PATH 里剩下的目录
62+
for p in os.environ["PATH"].split(os.pathsep):
63+
dirs.append(Path(p))
64+
65+
# 6. macOS Homebrew
66+
if sys.platform == "darwin":
67+
dirs.append(Path("/usr/local/bin"))
68+
dirs.append(Path("/opt/homebrew/bin"))
69+
70+
# 去重并保持顺序
71+
seen = set()
72+
return [d for d in dirs if not (d in seen or seen.add(d))]
73+
74+
75+
def locate_cmake_format() -> Path:
76+
"""
77+
返回 cmake-format 的绝对路径(pathlib.Path)。
78+
找不到抛 FileNotFoundError。
79+
"""
80+
exe_name = "cmake-format.exe" if sys.platform == "win32" else "cmake-format"
81+
82+
# 1. 快速通道
83+
if (hit := shutil.which(exe_name)) is not None:
84+
return Path(hit).resolve()
85+
86+
# 2. 兜底扫描
87+
for folder in _all_site_script_dirs():
88+
if not folder.is_dir():
89+
continue
90+
candidate = folder / exe_name
91+
if candidate.is_file() and os.access(candidate, os.X_OK):
92+
print(f"{Colors.BOLD}cmake-format{Colors.END}{candidate}")
93+
return candidate.resolve()
94+
95+
# 3. 真的找不到
96+
raise FileNotFoundError(
97+
"cmake-format 未找到。\n"
98+
"请先安装:\n"
99+
" python -m pip install -U cmake-format\n"
100+
"并确保所在目录在 PATH 中,或位于当前虚拟环境/用户脚本目录。"
101+
)
102+
103+
104+
def format_one(exe: Path, path: Path) -> None:
105+
try:
106+
subprocess.run([str(exe), "-i", str(path)], check=True)
107+
print(f"{Colors.OK}formatted {path}{Colors.END}")
108+
except subprocess.CalledProcessError as e:
109+
print(
110+
f"{Colors.ERR}ERROR {path} (return code {e.returncode}){Colors.END}",
111+
file=sys.stderr,
112+
)
113+
114+
115+
def find_and_format(exe: Path, root: Path, jobs: int) -> None:
116+
counter = 0
117+
118+
def _walk() -> Iterable[Path]:
119+
nonlocal counter
120+
for p in root.rglob("*.cmake"):
121+
if p.is_file():
122+
counter += 1
123+
yield p
124+
125+
with ThreadPoolExecutor(max_workers=jobs) as pool:
126+
# 把生成器直接扔给 executor.map,它内部会按需 next()
127+
pool.map(lambda f: format_one(exe, f), _walk())
128+
129+
if counter == 0:
130+
print(f"{Colors.WARN}未找到任何 .cmake 文件{Colors.END}")
131+
else:
132+
print(f"{Colors.BOLD}All done.{Colors.END}")
133+
134+
135+
def main() -> None:
136+
parser = argparse.ArgumentParser(description="批量格式化 .cmake 文件")
137+
parser.add_argument("target", help="单个 .cmake 文件或包含 .cmake 的目录")
138+
parser.add_argument(
139+
"-j",
140+
"--jobs",
141+
type=int,
142+
default=os.cpu_count(),
143+
help="并行线程数(默认:CPU 核心数)",
144+
)
145+
args = parser.parse_args()
146+
147+
target = Path(args.target).expanduser().resolve()
148+
if not target.exists():
149+
print(f"{Colors.ERR}路径不存在: {target}{Colors.END}", file=sys.stderr)
150+
sys.exit(2)
151+
152+
exe = locate_cmake_format()
153+
154+
# 单文件模式
155+
if target.is_file():
156+
format_one(exe, target)
157+
return
158+
159+
# 目录模式
160+
find_and_format(exe, target, args.jobs)
161+
162+
163+
if __name__ == "__main__":
164+
main()

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ authors = [
1313
license = { file = "LICENSE" }
1414
dependencies = [
1515
"blake3",
16+
"cmake_format",
1617
"loguru",
1718
"matplotlib",
1819
"paramiko",

syncthing/syncthing_monitor.py

Lines changed: 0 additions & 171 deletions
This file was deleted.

0 commit comments

Comments
 (0)