dcheckdev 0.1.0__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.
checkdev.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import psutil
|
|
7
|
+
from rich import box
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
# 真正的终端能自动测出宽度;PyCharm 运行窗口测不出,就固定按 200 宽排版
|
|
12
|
+
console = Console(width=None if sys.stdout.isatty() else 200)
|
|
13
|
+
|
|
14
|
+
# 要检查的工具:(显示名, 命令)
|
|
15
|
+
TOOLS = [
|
|
16
|
+
("Python", ["python", "--version"]),
|
|
17
|
+
("Go", ["go", "version"]),
|
|
18
|
+
("Node", ["node", "--version"]),
|
|
19
|
+
("Git", ["git", "--version"]),
|
|
20
|
+
("Java", ["java", "-version"]),
|
|
21
|
+
("Wails", ["wails", "version"]),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# 每个工具要查看的配置:工具名 -> [(配置名, 命令), ...]
|
|
25
|
+
CONFIGS = {
|
|
26
|
+
"Go": [
|
|
27
|
+
("GOROOT", ["go", "env", "GOROOT"]),
|
|
28
|
+
("GOPATH", ["go", "env", "GOPATH"]),
|
|
29
|
+
("GOPROXY", ["go", "env", "GOPROXY"]),
|
|
30
|
+
],
|
|
31
|
+
"Python": [
|
|
32
|
+
("pip 镜像", ["python", "-m", "pip", "config", "get", "global.index-url"]),
|
|
33
|
+
],
|
|
34
|
+
"Node": [
|
|
35
|
+
("npm 镜像", ["npm", "config", "get", "registry"]),
|
|
36
|
+
("全局目录", ["npm", "config", "get", "prefix"]),
|
|
37
|
+
],
|
|
38
|
+
"Git": [
|
|
39
|
+
("user.name", ["git", "config", "--global", "user.name"]),
|
|
40
|
+
("user.email", ["git", "config", "--global", "user.email"]),
|
|
41
|
+
],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# 直接读取的环境变量
|
|
45
|
+
ENV_VARS = ["JAVA_HOME"]
|
|
46
|
+
|
|
47
|
+
# 要检查的端口:端口号 -> 通常是谁在用
|
|
48
|
+
PORTS = {
|
|
49
|
+
8000: "FastAPI / Django",
|
|
50
|
+
8080: "Spring Boot / Tomcat",
|
|
51
|
+
5173: "Vite 前端",
|
|
52
|
+
3306: "MySQL",
|
|
53
|
+
5672: "RabbitMQ",
|
|
54
|
+
6379: "Redis",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def make_table(title, *columns):
|
|
59
|
+
"""创建统一样式的表格:没有竖线,每列都不折行,宽度按最长的文字"""
|
|
60
|
+
table = Table(title=title, box=box.SIMPLE_HEAD, title_justify="left")
|
|
61
|
+
for col in columns:
|
|
62
|
+
table.add_column(col, no_wrap=True)
|
|
63
|
+
return table
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def run(cmd):
|
|
67
|
+
"""运行命令,返回 (返回码, 第一行输出);没安装返回 None"""
|
|
68
|
+
exe = shutil.which(cmd[0])
|
|
69
|
+
if exe is None:
|
|
70
|
+
return None
|
|
71
|
+
try:
|
|
72
|
+
result = subprocess.run(
|
|
73
|
+
[exe] + cmd[1:],
|
|
74
|
+
capture_output=True,
|
|
75
|
+
text=True,
|
|
76
|
+
encoding="utf-8",
|
|
77
|
+
errors="replace",
|
|
78
|
+
timeout=10,
|
|
79
|
+
)
|
|
80
|
+
except subprocess.TimeoutExpired:
|
|
81
|
+
return -1, "超时"
|
|
82
|
+
|
|
83
|
+
output = (result.stdout or result.stderr).strip()
|
|
84
|
+
first_line = output.splitlines()[0] if output else ""
|
|
85
|
+
return result.returncode, first_line
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def check_tools():
|
|
89
|
+
table = make_table("1. 工具版本", "工具", "状态", "版本", "位置")
|
|
90
|
+
|
|
91
|
+
for name, cmd in TOOLS:
|
|
92
|
+
location = shutil.which(cmd[0]) or ""
|
|
93
|
+
res = run(cmd)
|
|
94
|
+
if res is None:
|
|
95
|
+
status, version = "[red]未安装[/red]", ""
|
|
96
|
+
elif res[0] == 0:
|
|
97
|
+
status, version = "[green]已安装[/green]", res[1]
|
|
98
|
+
else:
|
|
99
|
+
status, version = "[yellow]出错[/yellow]", res[1]
|
|
100
|
+
table.add_row(f"[bold]{name}[/bold]", status, version, f"[dim]{location}[/dim]")
|
|
101
|
+
|
|
102
|
+
console.print(table)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def check_path():
|
|
106
|
+
table = make_table("2. PATH 检查", "问题", "路径")
|
|
107
|
+
|
|
108
|
+
paths = os.environ.get("PATH", "").split(os.pathsep)
|
|
109
|
+
seen = set()
|
|
110
|
+
for raw in paths:
|
|
111
|
+
raw = raw.strip()
|
|
112
|
+
if not raw:
|
|
113
|
+
continue
|
|
114
|
+
p = os.path.expandvars(raw)
|
|
115
|
+
key = os.path.normcase(os.path.normpath(p))
|
|
116
|
+
if key in seen:
|
|
117
|
+
table.add_row("[yellow]重复[/yellow]", raw)
|
|
118
|
+
elif "%" in p:
|
|
119
|
+
table.add_row("[red]变量无法展开[/red]", raw)
|
|
120
|
+
elif os.path.isfile(p):
|
|
121
|
+
table.add_row("[yellow]是文件不是目录[/yellow]", raw)
|
|
122
|
+
elif not os.path.isdir(p):
|
|
123
|
+
table.add_row("[red]失效[/red]", raw)
|
|
124
|
+
seen.add(key)
|
|
125
|
+
|
|
126
|
+
if table.row_count == 0:
|
|
127
|
+
console.print(f"[green]2. PATH 检查:共 {len(paths)} 项,没有问题[/green]")
|
|
128
|
+
else:
|
|
129
|
+
table.caption = f"PATH 共 {len(paths)} 项,发现 {table.row_count} 个问题"
|
|
130
|
+
console.print(table)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def check_configs():
|
|
134
|
+
table = make_table("3. 关键配置", "工具", "配置", "值")
|
|
135
|
+
|
|
136
|
+
for tool, items in CONFIGS.items():
|
|
137
|
+
for label, cmd in items:
|
|
138
|
+
res = run(cmd)
|
|
139
|
+
if res is None:
|
|
140
|
+
table.add_row(tool, label, f"[dim]没找到 {cmd[0]},跳过[/dim]")
|
|
141
|
+
break
|
|
142
|
+
if res[0] == 0 and res[1]:
|
|
143
|
+
value = res[1]
|
|
144
|
+
else:
|
|
145
|
+
value = "[yellow](未设置)[/yellow]"
|
|
146
|
+
table.add_row(f"[bold]{tool}[/bold]", label, value)
|
|
147
|
+
|
|
148
|
+
for name in ENV_VARS:
|
|
149
|
+
value = os.environ.get(name) or "[yellow](未设置)[/yellow]"
|
|
150
|
+
table.add_row("[bold]环境变量[/bold]", name, value)
|
|
151
|
+
|
|
152
|
+
console.print(table)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def find_listeners():
|
|
156
|
+
"""返回 {端口: 进程 PID},只看正在监听的 TCP 端口"""
|
|
157
|
+
listeners = {}
|
|
158
|
+
for conn in psutil.net_connections(kind="tcp"):
|
|
159
|
+
if conn.status == psutil.CONN_LISTEN and conn.laddr:
|
|
160
|
+
listeners.setdefault(conn.laddr.port, conn.pid)
|
|
161
|
+
return listeners
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def process_name(pid):
|
|
165
|
+
"""根据 PID 查进程名,查不到返回问号"""
|
|
166
|
+
if not pid:
|
|
167
|
+
return "?"
|
|
168
|
+
try:
|
|
169
|
+
return psutil.Process(pid).name()
|
|
170
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
171
|
+
return "?"
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def check_ports():
|
|
175
|
+
table = make_table("4. 端口占用", "端口", "用途", "状态", "占用程序")
|
|
176
|
+
table.columns[0].justify = "right"
|
|
177
|
+
|
|
178
|
+
listeners = find_listeners()
|
|
179
|
+
for port, usage in PORTS.items():
|
|
180
|
+
if port in listeners:
|
|
181
|
+
pid = listeners[port]
|
|
182
|
+
table.add_row(str(port), usage, "[yellow]占用[/yellow]",
|
|
183
|
+
f"{process_name(pid)} (PID {pid})")
|
|
184
|
+
else:
|
|
185
|
+
table.add_row(str(port), usage, "[green]空闲[/green]", "")
|
|
186
|
+
|
|
187
|
+
console.print(table)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def main():
|
|
191
|
+
check_tools()
|
|
192
|
+
check_path()
|
|
193
|
+
check_configs()
|
|
194
|
+
check_ports()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
main()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dcheckdev
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: One-command local dev environment checker: tool versions, PATH, key configs and port usage
|
|
5
|
+
Author: dongzhongcen
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dongzhongcen
|
|
8
|
+
Keywords: cli,devtools,environment,path,windows
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Topic :: Software Development
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: rich
|
|
17
|
+
Requires-Dist: psutil
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# dcheckdev
|
|
21
|
+
|
|
22
|
+
一键检查本地开发环境的命令行工具。 / A one-command local dev environment checker.
|
|
23
|
+
|
|
24
|
+
## 简介
|
|
25
|
+
|
|
26
|
+
`dcheckdev` 会用彩色表格列出:
|
|
27
|
+
|
|
28
|
+
1. **工具版本**:Python、Go、Node、Git、Java、Wails 是否安装、版本号和实际使用的位置
|
|
29
|
+
2. **PATH 检查**:重复、失效、变量无法展开、误把文件写进 PATH 的条目
|
|
30
|
+
3. **关键配置**:GOROOT / GOPATH / GOPROXY、pip 镜像、npm 镜像和全局目录、Git 用户名和邮箱、JAVA_HOME
|
|
31
|
+
4. **端口占用**:8000、8080、5173、3306、5672、6379 是否被占用,以及占用的程序
|
|
32
|
+
|
|
33
|
+
### 安装
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
python -m pip install dcheckdev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 使用
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
devcheck
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
建议在 PowerShell、Windows Terminal 等真正的终端里运行,颜色显示最完整。
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Overview
|
|
50
|
+
|
|
51
|
+
`dcheckdev` prints colored tables showing:
|
|
52
|
+
|
|
53
|
+
1. **Tool versions**: whether Python, Go, Node, Git, Java and Wails are installed, their versions and which executable is actually used
|
|
54
|
+
2. **PATH check**: duplicate, missing, unexpanded-variable and file-instead-of-directory entries
|
|
55
|
+
3. **Key configs**: GOROOT / GOPATH / GOPROXY, pip index, npm registry and global prefix, Git user name and email, JAVA_HOME
|
|
56
|
+
4. **Port usage**: whether ports 8000, 8080, 5173, 3306, 5672 and 6379 are in use, and by which process
|
|
57
|
+
|
|
58
|
+
### Install
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
python -m pip install dcheckdev
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Usage
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
devcheck
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
checkdev.py,sha256=8YRpLHpYJ0dRNmebLGaYNtdPfhDIg2Mx68GMicZ1-Mw,5901
|
|
2
|
+
dcheckdev-0.1.0.dist-info/licenses/LICENSE,sha256=MgRS43voHFNBfApVAUys1wwJL8aVk79str6vtQ1jacA,1069
|
|
3
|
+
dcheckdev-0.1.0.dist-info/METADATA,sha256=WAvibpQRJ5OnTLlYB0T85xL3cPPxepWOVIVGeoTOunk,2041
|
|
4
|
+
dcheckdev-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
5
|
+
dcheckdev-0.1.0.dist-info/entry_points.txt,sha256=V06FywvcuFON36OJpBP9u7k5j80tZ0-i4nrCnzksow8,43
|
|
6
|
+
dcheckdev-0.1.0.dist-info/top_level.txt,sha256=FgCTAotE_eUOZ_gdLhg2YUfRrMXS46Vxodx3dv0Dkaw,9
|
|
7
|
+
dcheckdev-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dongzhongcen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
checkdev
|