dcheckdev 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- dcheckdev-0.2.0/PKG-INFO +99 -0
- dcheckdev-0.2.0/README.md +80 -0
- dcheckdev-0.2.0/checkdev.py +423 -0
- dcheckdev-0.2.0/dcheckdev.egg-info/PKG-INFO +99 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/pyproject.toml +1 -1
- dcheckdev-0.1.0/PKG-INFO +0 -72
- dcheckdev-0.1.0/README.md +0 -53
- dcheckdev-0.1.0/checkdev.py +0 -198
- dcheckdev-0.1.0/dcheckdev.egg-info/PKG-INFO +0 -72
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/LICENSE +0 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/dcheckdev.egg-info/SOURCES.txt +0 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/dcheckdev.egg-info/dependency_links.txt +0 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/dcheckdev.egg-info/entry_points.txt +0 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/dcheckdev.egg-info/requires.txt +0 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/dcheckdev.egg-info/top_level.txt +0 -0
- {dcheckdev-0.1.0 → dcheckdev-0.2.0}/setup.cfg +0 -0
dcheckdev-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dcheckdev
|
|
3
|
+
Version: 0.2.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. **工具版本**:对照内置「常见工具目录」,用 `PATH`(`shutil.which`)自动探测已安装项,并显示版本号与可执行文件位置;未命中的目录项会跳过,不会扫描整条 PATH
|
|
29
|
+
2. **PATH 检查**:重复、失效、变量无法展开、误把文件写进 PATH 的条目
|
|
30
|
+
3. **关键配置**:仅为已检测到的工具展示配置探针(如 Go 环境、pip/npm 镜像、Git 用户信息、Docker Compose 插件等);环境变量(如 JAVA_HOME)在已设置或关联工具已安装时显示
|
|
31
|
+
4. **端口占用**:8000、8080、5173、3306、5672、6379 是否被占用,以及占用的程序
|
|
32
|
+
|
|
33
|
+
目录示例(节选):python / python3、go、node、npm、git、java / javac、wails、docker、docker-compose、kubectl、rustc / cargo、gcc / clang、make / cmake、mvn / gradle、code、curl / wget / ssh、mysql / redis-cli / psql、pip / pip3、yarn / pnpm / bun / deno、php、ruby、dotnet、terraform、aws、gh 等。
|
|
34
|
+
|
|
35
|
+
从 **0.2.0** 起:交互式终端中运行 `devcheck` 会先播放简短开场动画,再进入编号菜单;工具列表改为目录 + PATH 自动探测;选择「各工具路径与关键配置」时,二级菜单只列出当前有内容可看的分组(并保留「全部配置」)。
|
|
36
|
+
|
|
37
|
+
若 stdin 或 stdout 不是 TTY(例如 CI、管道重定向),则自动退回:一次跑完全部检查,不进入菜单、不挂起等待输入。
|
|
38
|
+
|
|
39
|
+
### 安装
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
python -m pip install dcheckdev
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 使用
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
devcheck
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
交互菜单(TTY):
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
1. 工具版本
|
|
55
|
+
2. PATH 检查
|
|
56
|
+
3. 各工具路径与关键配置
|
|
57
|
+
4. 端口占用
|
|
58
|
+
5. 全部跑一遍
|
|
59
|
+
0. 退出
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
非交互(管道 / CI):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
devcheck </dev/null
|
|
66
|
+
# 或
|
|
67
|
+
python checkdev.py </dev/null
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
建议在 PowerShell、Windows Terminal 等真正的终端里运行,颜色显示最完整。
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Overview
|
|
75
|
+
|
|
76
|
+
`dcheckdev` prints colored tables showing:
|
|
77
|
+
|
|
78
|
+
1. **Tool versions**: auto-detects installed tools from a built-in common catalog via `PATH` (`shutil.which`); shows version and executable path; skips missing catalog entries (does not scan every PATH executable)
|
|
79
|
+
2. **PATH check**: duplicate, missing, unexpanded-variable and file-instead-of-directory entries
|
|
80
|
+
3. **Key configs**: probes only for detected tools (Go env, pip/npm registry, Git identity, Docker Compose plugin, etc.); env vars such as `JAVA_HOME` appear when set or when a related tool is installed
|
|
81
|
+
4. **Port usage**: whether ports 8000, 8080, 5173, 3306, 5672 and 6379 are in use, and by which process
|
|
82
|
+
|
|
83
|
+
From **0.2.0**, in an interactive TTY `devcheck` shows a short opening animation and a numbered menu. Option 3 only lists config subgroups that have something to show (plus "all configs"). When stdin or stdout is not a TTY (CI, pipes), it falls back to running all checks once without prompting.
|
|
84
|
+
|
|
85
|
+
### Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python -m pip install dcheckdev
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Usage
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
devcheck
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
MIT
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# dcheckdev
|
|
2
|
+
|
|
3
|
+
一键检查本地开发环境的命令行工具。 / A one-command local dev environment checker.
|
|
4
|
+
|
|
5
|
+
## 简介
|
|
6
|
+
|
|
7
|
+
`dcheckdev` 会用彩色表格列出:
|
|
8
|
+
|
|
9
|
+
1. **工具版本**:对照内置「常见工具目录」,用 `PATH`(`shutil.which`)自动探测已安装项,并显示版本号与可执行文件位置;未命中的目录项会跳过,不会扫描整条 PATH
|
|
10
|
+
2. **PATH 检查**:重复、失效、变量无法展开、误把文件写进 PATH 的条目
|
|
11
|
+
3. **关键配置**:仅为已检测到的工具展示配置探针(如 Go 环境、pip/npm 镜像、Git 用户信息、Docker Compose 插件等);环境变量(如 JAVA_HOME)在已设置或关联工具已安装时显示
|
|
12
|
+
4. **端口占用**:8000、8080、5173、3306、5672、6379 是否被占用,以及占用的程序
|
|
13
|
+
|
|
14
|
+
目录示例(节选):python / python3、go、node、npm、git、java / javac、wails、docker、docker-compose、kubectl、rustc / cargo、gcc / clang、make / cmake、mvn / gradle、code、curl / wget / ssh、mysql / redis-cli / psql、pip / pip3、yarn / pnpm / bun / deno、php、ruby、dotnet、terraform、aws、gh 等。
|
|
15
|
+
|
|
16
|
+
从 **0.2.0** 起:交互式终端中运行 `devcheck` 会先播放简短开场动画,再进入编号菜单;工具列表改为目录 + PATH 自动探测;选择「各工具路径与关键配置」时,二级菜单只列出当前有内容可看的分组(并保留「全部配置」)。
|
|
17
|
+
|
|
18
|
+
若 stdin 或 stdout 不是 TTY(例如 CI、管道重定向),则自动退回:一次跑完全部检查,不进入菜单、不挂起等待输入。
|
|
19
|
+
|
|
20
|
+
### 安装
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python -m pip install dcheckdev
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 使用
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
devcheck
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
交互菜单(TTY):
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
1. 工具版本
|
|
36
|
+
2. PATH 检查
|
|
37
|
+
3. 各工具路径与关键配置
|
|
38
|
+
4. 端口占用
|
|
39
|
+
5. 全部跑一遍
|
|
40
|
+
0. 退出
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
非交互(管道 / CI):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
devcheck </dev/null
|
|
47
|
+
# 或
|
|
48
|
+
python checkdev.py </dev/null
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
建议在 PowerShell、Windows Terminal 等真正的终端里运行,颜色显示最完整。
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Overview
|
|
56
|
+
|
|
57
|
+
`dcheckdev` prints colored tables showing:
|
|
58
|
+
|
|
59
|
+
1. **Tool versions**: auto-detects installed tools from a built-in common catalog via `PATH` (`shutil.which`); shows version and executable path; skips missing catalog entries (does not scan every PATH executable)
|
|
60
|
+
2. **PATH check**: duplicate, missing, unexpanded-variable and file-instead-of-directory entries
|
|
61
|
+
3. **Key configs**: probes only for detected tools (Go env, pip/npm registry, Git identity, Docker Compose plugin, etc.); env vars such as `JAVA_HOME` appear when set or when a related tool is installed
|
|
62
|
+
4. **Port usage**: whether ports 8000, 8080, 5173, 3306, 5672 and 6379 are in use, and by which process
|
|
63
|
+
|
|
64
|
+
From **0.2.0**, in an interactive TTY `devcheck` shows a short opening animation and a numbered menu. Option 3 only lists config subgroups that have something to show (plus "all configs"). When stdin or stdout is not a TTY (CI, pipes), it falls back to running all checks once without prompting.
|
|
65
|
+
|
|
66
|
+
### Install
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python -m pip install dcheckdev
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Usage
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
devcheck
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
import psutil
|
|
9
|
+
from rich import box
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
# 真正的终端能自动测出宽度;PyCharm 运行窗口测不出,就固定按 200 宽排版
|
|
14
|
+
console = Console(width=None if sys.stdout.isatty() else 200)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class Tool:
|
|
19
|
+
"""常见开发工具目录项:显示名、版本检查 argv、可选配置探针。"""
|
|
20
|
+
|
|
21
|
+
name: str
|
|
22
|
+
cmd: list # e.g. ["docker", "--version"];用 cmd[0] 做 PATH 探测
|
|
23
|
+
configs: tuple = () # ((配置名, argv), ...)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# 常见工具目录(不扫整条 PATH,只查这一批)
|
|
27
|
+
COMMON_TOOLS = [
|
|
28
|
+
Tool("Python", ["python", "--version"], (
|
|
29
|
+
("pip 镜像", ["python", "-m", "pip", "config", "get", "global.index-url"]),
|
|
30
|
+
)),
|
|
31
|
+
Tool("Python3", ["python3", "--version"], (
|
|
32
|
+
("pip 镜像", ["python3", "-m", "pip", "config", "get", "global.index-url"]),
|
|
33
|
+
)),
|
|
34
|
+
Tool("pip", ["pip", "--version"]),
|
|
35
|
+
Tool("pip3", ["pip3", "--version"]),
|
|
36
|
+
Tool("Go", ["go", "version"], (
|
|
37
|
+
("GOROOT", ["go", "env", "GOROOT"]),
|
|
38
|
+
("GOPATH", ["go", "env", "GOPATH"]),
|
|
39
|
+
("GOPROXY", ["go", "env", "GOPROXY"]),
|
|
40
|
+
)),
|
|
41
|
+
Tool("Node", ["node", "--version"]),
|
|
42
|
+
Tool("npm", ["npm", "--version"], (
|
|
43
|
+
("npm 镜像", ["npm", "config", "get", "registry"]),
|
|
44
|
+
("全局目录", ["npm", "config", "get", "prefix"]),
|
|
45
|
+
)),
|
|
46
|
+
Tool("yarn", ["yarn", "--version"]),
|
|
47
|
+
Tool("pnpm", ["pnpm", "--version"]),
|
|
48
|
+
Tool("bun", ["bun", "--version"]),
|
|
49
|
+
Tool("deno", ["deno", "--version"]),
|
|
50
|
+
Tool("Git", ["git", "--version"], (
|
|
51
|
+
("user.name", ["git", "config", "--global", "user.name"]),
|
|
52
|
+
("user.email", ["git", "config", "--global", "user.email"]),
|
|
53
|
+
)),
|
|
54
|
+
Tool("Java", ["java", "-version"]),
|
|
55
|
+
Tool("javac", ["javac", "-version"]),
|
|
56
|
+
Tool("Wails", ["wails", "version"]),
|
|
57
|
+
Tool("Docker", ["docker", "--version"], (
|
|
58
|
+
("compose 插件", ["docker", "compose", "version"]),
|
|
59
|
+
)),
|
|
60
|
+
Tool("Docker Compose", ["docker-compose", "--version"]),
|
|
61
|
+
Tool("kubectl", ["kubectl", "version", "--client"]),
|
|
62
|
+
Tool("rustc", ["rustc", "--version"]),
|
|
63
|
+
Tool("cargo", ["cargo", "--version"]),
|
|
64
|
+
Tool("gcc", ["gcc", "--version"]),
|
|
65
|
+
Tool("clang", ["clang", "--version"]),
|
|
66
|
+
Tool("make", ["make", "--version"]),
|
|
67
|
+
Tool("cmake", ["cmake", "--version"]),
|
|
68
|
+
Tool("Maven", ["mvn", "--version"]),
|
|
69
|
+
Tool("Gradle", ["gradle", "--version"]),
|
|
70
|
+
Tool("VS Code", ["code", "--version"]),
|
|
71
|
+
Tool("curl", ["curl", "--version"]),
|
|
72
|
+
Tool("wget", ["wget", "--version"]),
|
|
73
|
+
Tool("ssh", ["ssh", "-V"]),
|
|
74
|
+
Tool("MySQL", ["mysql", "--version"]),
|
|
75
|
+
Tool("redis-cli", ["redis-cli", "--version"]),
|
|
76
|
+
Tool("psql", ["psql", "--version"]),
|
|
77
|
+
Tool("PHP", ["php", "--version"]),
|
|
78
|
+
Tool("Ruby", ["ruby", "--version"]),
|
|
79
|
+
Tool(".NET", ["dotnet", "--version"]),
|
|
80
|
+
Tool("Terraform", ["terraform", "version"]),
|
|
81
|
+
Tool("AWS CLI", ["aws", "--version"]),
|
|
82
|
+
Tool("GitHub CLI", ["gh", "--version"]),
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
# 环境变量:(变量名, 关联工具的 cmd[0] 列表;任一在 PATH 上或变量已设置则展示)
|
|
86
|
+
ENV_VARS = [
|
|
87
|
+
("JAVA_HOME", ("java", "javac")),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# 要检查的端口:端口号 -> 通常是谁在用
|
|
91
|
+
PORTS = {
|
|
92
|
+
8000: "FastAPI / Django",
|
|
93
|
+
8080: "Spring Boot / Tomcat",
|
|
94
|
+
5173: "Vite 前端",
|
|
95
|
+
3306: "MySQL",
|
|
96
|
+
5672: "RabbitMQ",
|
|
97
|
+
6379: "Redis",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def resolve_installed_tools():
|
|
102
|
+
"""从 COMMON_TOOLS 中筛出 PATH 上存在的工具(shutil.which)。"""
|
|
103
|
+
return [t for t in COMMON_TOOLS if shutil.which(t.cmd[0])]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def make_table(title, *columns):
|
|
107
|
+
"""创建统一样式的表格:没有竖线,每列都不折行,宽度按最长的文字"""
|
|
108
|
+
table = Table(title=title, box=box.SIMPLE_HEAD, title_justify="left")
|
|
109
|
+
for col in columns:
|
|
110
|
+
table.add_column(col, no_wrap=True)
|
|
111
|
+
return table
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def run(cmd):
|
|
115
|
+
"""运行命令,返回 (返回码, 第一行输出);没安装返回 None"""
|
|
116
|
+
exe = shutil.which(cmd[0])
|
|
117
|
+
if exe is None:
|
|
118
|
+
return None
|
|
119
|
+
try:
|
|
120
|
+
result = subprocess.run(
|
|
121
|
+
[exe] + cmd[1:],
|
|
122
|
+
capture_output=True,
|
|
123
|
+
text=True,
|
|
124
|
+
encoding="utf-8",
|
|
125
|
+
errors="replace",
|
|
126
|
+
timeout=10,
|
|
127
|
+
)
|
|
128
|
+
except subprocess.TimeoutExpired:
|
|
129
|
+
return -1, "超时"
|
|
130
|
+
except OSError:
|
|
131
|
+
return -1, "无法执行"
|
|
132
|
+
|
|
133
|
+
output = (result.stdout or result.stderr).strip()
|
|
134
|
+
first_line = output.splitlines()[0] if output else ""
|
|
135
|
+
return result.returncode, first_line
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def check_tools(installed=None):
|
|
139
|
+
if installed is None:
|
|
140
|
+
installed = resolve_installed_tools()
|
|
141
|
+
|
|
142
|
+
if not installed:
|
|
143
|
+
console.print("[yellow]1. 工具版本:未在 PATH 中检测到常见开发工具。[/yellow]")
|
|
144
|
+
console.print("[dim](已对照内置目录探测,不会扫描整条 PATH。)[/dim]")
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
table = make_table("1. 工具版本(已检测到)", "工具", "状态", "版本", "位置")
|
|
148
|
+
|
|
149
|
+
for tool in installed:
|
|
150
|
+
location = shutil.which(tool.cmd[0]) or ""
|
|
151
|
+
res = run(tool.cmd)
|
|
152
|
+
# 已通过 which 命中;有输出或 exit 0 视为已安装(ssh -V 等常写 stderr 且非 0)
|
|
153
|
+
if res is None:
|
|
154
|
+
status, version = "[red]未安装[/red]", ""
|
|
155
|
+
elif res[1] or res[0] == 0:
|
|
156
|
+
status, version = "[green]已安装[/green]", res[1] or f"(exit {res[0]})"
|
|
157
|
+
else:
|
|
158
|
+
status, version = "[yellow]出错[/yellow]", res[1]
|
|
159
|
+
table.add_row(f"[bold]{tool.name}[/bold]", status, version, f"[dim]{location}[/dim]")
|
|
160
|
+
|
|
161
|
+
table.caption = f"目录共 {len(COMMON_TOOLS)} 项,PATH 命中 {len(installed)} 项"
|
|
162
|
+
console.print(table)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def check_path():
|
|
166
|
+
table = make_table("2. PATH 检查", "问题", "路径")
|
|
167
|
+
|
|
168
|
+
paths = os.environ.get("PATH", "").split(os.pathsep)
|
|
169
|
+
seen = set()
|
|
170
|
+
for raw in paths:
|
|
171
|
+
raw = raw.strip()
|
|
172
|
+
if not raw:
|
|
173
|
+
continue
|
|
174
|
+
p = os.path.expandvars(raw)
|
|
175
|
+
key = os.path.normcase(os.path.normpath(p))
|
|
176
|
+
if key in seen:
|
|
177
|
+
table.add_row("[yellow]重复[/yellow]", raw)
|
|
178
|
+
elif "%" in p:
|
|
179
|
+
table.add_row("[red]变量无法展开[/red]", raw)
|
|
180
|
+
elif os.path.isfile(p):
|
|
181
|
+
table.add_row("[yellow]是文件不是目录[/yellow]", raw)
|
|
182
|
+
elif not os.path.isdir(p):
|
|
183
|
+
table.add_row("[red]失效[/red]", raw)
|
|
184
|
+
seen.add(key)
|
|
185
|
+
|
|
186
|
+
if table.row_count == 0:
|
|
187
|
+
console.print(f"[green]2. PATH 检查:共 {len(paths)} 项,没有问题[/green]")
|
|
188
|
+
else:
|
|
189
|
+
table.caption = f"PATH 共 {len(paths)} 项,发现 {table.row_count} 个问题"
|
|
190
|
+
console.print(table)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _env_vars_to_show(installed):
|
|
194
|
+
"""环境变量:已设置,或关联工具已安装时展示。"""
|
|
195
|
+
installed_bins = {t.cmd[0] for t in installed}
|
|
196
|
+
rows = []
|
|
197
|
+
for name, related in ENV_VARS:
|
|
198
|
+
value = os.environ.get(name)
|
|
199
|
+
related_hit = any(b in installed_bins for b in related)
|
|
200
|
+
if value or related_hit:
|
|
201
|
+
rows.append((name, value or "[yellow](未设置)[/yellow]"))
|
|
202
|
+
return rows
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _tools_with_configs(installed):
|
|
206
|
+
"""已安装且带有配置探针的工具。"""
|
|
207
|
+
return [t for t in installed if t.configs]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def check_configs(group=None, installed=None):
|
|
211
|
+
"""检查关键配置。
|
|
212
|
+
|
|
213
|
+
group:
|
|
214
|
+
None — 全部(已安装工具的 configs + 可见 ENV_VARS)
|
|
215
|
+
"env" — 仅环境变量
|
|
216
|
+
工具名 — 仅该工具的 configs
|
|
217
|
+
"""
|
|
218
|
+
if installed is None:
|
|
219
|
+
installed = resolve_installed_tools()
|
|
220
|
+
|
|
221
|
+
if group is None:
|
|
222
|
+
title = "3. 关键配置"
|
|
223
|
+
elif group == "env":
|
|
224
|
+
title = "3. 关键配置 · 环境变量"
|
|
225
|
+
else:
|
|
226
|
+
title = f"3. 关键配置 · {group}"
|
|
227
|
+
|
|
228
|
+
table = make_table(title, "工具", "配置", "值")
|
|
229
|
+
|
|
230
|
+
include_configs = group is None or (group != "env")
|
|
231
|
+
include_env = group is None or group == "env"
|
|
232
|
+
|
|
233
|
+
if include_configs:
|
|
234
|
+
tools = _tools_with_configs(installed)
|
|
235
|
+
if group is not None and group != "env":
|
|
236
|
+
tools = [t for t in tools if t.name == group]
|
|
237
|
+
for tool in tools:
|
|
238
|
+
for label, cmd in tool.configs:
|
|
239
|
+
res = run(cmd)
|
|
240
|
+
if res is None:
|
|
241
|
+
table.add_row(tool.name, label, f"[dim]没找到 {cmd[0]},跳过[/dim]")
|
|
242
|
+
break
|
|
243
|
+
if res[0] == 0 and res[1]:
|
|
244
|
+
value = res[1]
|
|
245
|
+
else:
|
|
246
|
+
value = "[yellow](未设置)[/yellow]"
|
|
247
|
+
table.add_row(f"[bold]{tool.name}[/bold]", label, value)
|
|
248
|
+
|
|
249
|
+
if include_env:
|
|
250
|
+
for name, value in _env_vars_to_show(installed):
|
|
251
|
+
table.add_row("[bold]环境变量[/bold]", name, value)
|
|
252
|
+
|
|
253
|
+
if table.row_count == 0:
|
|
254
|
+
console.print(f"[yellow]{title}:当前没有可展示的配置项。[/yellow]")
|
|
255
|
+
else:
|
|
256
|
+
console.print(table)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def build_config_groups(installed=None):
|
|
260
|
+
"""选项 3 二级菜单:只列出有内容可看的分组,并始终保留「全部配置」。"""
|
|
261
|
+
if installed is None:
|
|
262
|
+
installed = resolve_installed_tools()
|
|
263
|
+
|
|
264
|
+
groups = []
|
|
265
|
+
n = 1
|
|
266
|
+
for tool in _tools_with_configs(installed):
|
|
267
|
+
groups.append((str(n), tool.name, tool.name))
|
|
268
|
+
n += 1
|
|
269
|
+
|
|
270
|
+
if _env_vars_to_show(installed):
|
|
271
|
+
groups.append((str(n), "环境变量", "env"))
|
|
272
|
+
n += 1
|
|
273
|
+
|
|
274
|
+
groups.append((str(n), "全部配置", None))
|
|
275
|
+
return groups
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def find_listeners():
|
|
279
|
+
"""返回 {端口: 进程 PID},只看正在监听的 TCP 端口"""
|
|
280
|
+
listeners = {}
|
|
281
|
+
for conn in psutil.net_connections(kind="tcp"):
|
|
282
|
+
if conn.status == psutil.CONN_LISTEN and conn.laddr:
|
|
283
|
+
listeners.setdefault(conn.laddr.port, conn.pid)
|
|
284
|
+
return listeners
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def process_name(pid):
|
|
288
|
+
"""根据 PID 查进程名,查不到返回问号"""
|
|
289
|
+
if not pid:
|
|
290
|
+
return "?"
|
|
291
|
+
try:
|
|
292
|
+
return psutil.Process(pid).name()
|
|
293
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
294
|
+
return "?"
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def check_ports():
|
|
298
|
+
table = make_table("4. 端口占用", "端口", "用途", "状态", "占用程序")
|
|
299
|
+
table.columns[0].justify = "right"
|
|
300
|
+
|
|
301
|
+
listeners = find_listeners()
|
|
302
|
+
for port, usage in PORTS.items():
|
|
303
|
+
if port in listeners:
|
|
304
|
+
pid = listeners[port]
|
|
305
|
+
table.add_row(str(port), usage, "[yellow]占用[/yellow]",
|
|
306
|
+
f"{process_name(pid)} (PID {pid})")
|
|
307
|
+
else:
|
|
308
|
+
table.add_row(str(port), usage, "[green]空闲[/green]", "")
|
|
309
|
+
|
|
310
|
+
console.print(table)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def run_all():
|
|
314
|
+
"""跑全部检查(非交互 / 菜单选项 5)"""
|
|
315
|
+
installed = resolve_installed_tools()
|
|
316
|
+
check_tools(installed)
|
|
317
|
+
check_path()
|
|
318
|
+
check_configs(installed=installed)
|
|
319
|
+
check_ports()
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def play_opening():
|
|
323
|
+
"""短开场动画:纯终端 ASCII/Unicode,约 1–2 秒,无网络。"""
|
|
324
|
+
frames = [
|
|
325
|
+
" · · ·",
|
|
326
|
+
" ○ · ·",
|
|
327
|
+
" ● ○ ·",
|
|
328
|
+
" ✓ ● ○",
|
|
329
|
+
" ✓ ✓ ●",
|
|
330
|
+
" ✓ ✓ ✓",
|
|
331
|
+
]
|
|
332
|
+
console.print()
|
|
333
|
+
console.print("[bold cyan] dcheckdev[/bold cyan] [dim]开发环境检查[/dim]")
|
|
334
|
+
for frame in frames:
|
|
335
|
+
console.print(f"\r [cyan]{frame}[/cyan] 准备中…", end="")
|
|
336
|
+
time.sleep(0.22)
|
|
337
|
+
console.print()
|
|
338
|
+
time.sleep(0.15)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def clear_screen():
|
|
342
|
+
console.clear()
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def show_menu():
|
|
346
|
+
console.print()
|
|
347
|
+
console.print("[bold]请选择检查项:[/bold]")
|
|
348
|
+
console.print(" [cyan]1[/cyan]. 工具版本")
|
|
349
|
+
console.print(" [cyan]2[/cyan]. PATH 检查")
|
|
350
|
+
console.print(" [cyan]3[/cyan]. 各工具路径与关键配置")
|
|
351
|
+
console.print(" [cyan]4[/cyan]. 端口占用")
|
|
352
|
+
console.print(" [cyan]5[/cyan]. 全部跑一遍")
|
|
353
|
+
console.print(" [cyan]0[/cyan]. 退出")
|
|
354
|
+
console.print()
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def prompt_config_group(installed=None):
|
|
358
|
+
"""选项 3 的二级菜单:选配置分组。返回 filter 键或 None(全部)。取消返回 False。"""
|
|
359
|
+
groups = build_config_groups(installed)
|
|
360
|
+
console.print()
|
|
361
|
+
console.print("[bold]查询哪一组配置?[/bold]")
|
|
362
|
+
for key, label, _ in groups:
|
|
363
|
+
console.print(f" [cyan]{key}[/cyan]. {label}")
|
|
364
|
+
console.print(" [cyan]0[/cyan]. 返回上级")
|
|
365
|
+
console.print()
|
|
366
|
+
choice = input("请输入编号: ").strip()
|
|
367
|
+
if choice == "0":
|
|
368
|
+
return False
|
|
369
|
+
for key, _label, group in groups:
|
|
370
|
+
if choice == key:
|
|
371
|
+
return group
|
|
372
|
+
console.print("[yellow]无效选项,请重试。[/yellow]")
|
|
373
|
+
return False
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def interactive_loop():
|
|
377
|
+
while True:
|
|
378
|
+
show_menu()
|
|
379
|
+
try:
|
|
380
|
+
choice = input("请输入编号: ").strip()
|
|
381
|
+
except EOFError:
|
|
382
|
+
console.print()
|
|
383
|
+
break
|
|
384
|
+
|
|
385
|
+
if choice == "0":
|
|
386
|
+
console.print("[dim]再见![/dim]")
|
|
387
|
+
break
|
|
388
|
+
elif choice == "1":
|
|
389
|
+
console.print()
|
|
390
|
+
check_tools()
|
|
391
|
+
elif choice == "2":
|
|
392
|
+
console.print()
|
|
393
|
+
check_path()
|
|
394
|
+
elif choice == "3":
|
|
395
|
+
installed = resolve_installed_tools()
|
|
396
|
+
group = prompt_config_group(installed)
|
|
397
|
+
if group is False:
|
|
398
|
+
continue
|
|
399
|
+
console.print()
|
|
400
|
+
check_configs(group, installed=installed)
|
|
401
|
+
elif choice == "4":
|
|
402
|
+
console.print()
|
|
403
|
+
check_ports()
|
|
404
|
+
elif choice == "5":
|
|
405
|
+
console.print()
|
|
406
|
+
run_all()
|
|
407
|
+
else:
|
|
408
|
+
console.print("[yellow]无效选项,请输入 0–5。[/yellow]")
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def main():
|
|
412
|
+
# 非 TTY(CI / 管道):保持旧行为,一次跑完全部,不挂起等输入
|
|
413
|
+
if not sys.stdin.isatty() or not sys.stdout.isatty():
|
|
414
|
+
run_all()
|
|
415
|
+
return
|
|
416
|
+
|
|
417
|
+
play_opening()
|
|
418
|
+
clear_screen()
|
|
419
|
+
interactive_loop()
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
if __name__ == "__main__":
|
|
423
|
+
main()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dcheckdev
|
|
3
|
+
Version: 0.2.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. **工具版本**:对照内置「常见工具目录」,用 `PATH`(`shutil.which`)自动探测已安装项,并显示版本号与可执行文件位置;未命中的目录项会跳过,不会扫描整条 PATH
|
|
29
|
+
2. **PATH 检查**:重复、失效、变量无法展开、误把文件写进 PATH 的条目
|
|
30
|
+
3. **关键配置**:仅为已检测到的工具展示配置探针(如 Go 环境、pip/npm 镜像、Git 用户信息、Docker Compose 插件等);环境变量(如 JAVA_HOME)在已设置或关联工具已安装时显示
|
|
31
|
+
4. **端口占用**:8000、8080、5173、3306、5672、6379 是否被占用,以及占用的程序
|
|
32
|
+
|
|
33
|
+
目录示例(节选):python / python3、go、node、npm、git、java / javac、wails、docker、docker-compose、kubectl、rustc / cargo、gcc / clang、make / cmake、mvn / gradle、code、curl / wget / ssh、mysql / redis-cli / psql、pip / pip3、yarn / pnpm / bun / deno、php、ruby、dotnet、terraform、aws、gh 等。
|
|
34
|
+
|
|
35
|
+
从 **0.2.0** 起:交互式终端中运行 `devcheck` 会先播放简短开场动画,再进入编号菜单;工具列表改为目录 + PATH 自动探测;选择「各工具路径与关键配置」时,二级菜单只列出当前有内容可看的分组(并保留「全部配置」)。
|
|
36
|
+
|
|
37
|
+
若 stdin 或 stdout 不是 TTY(例如 CI、管道重定向),则自动退回:一次跑完全部检查,不进入菜单、不挂起等待输入。
|
|
38
|
+
|
|
39
|
+
### 安装
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
python -m pip install dcheckdev
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 使用
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
devcheck
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
交互菜单(TTY):
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
1. 工具版本
|
|
55
|
+
2. PATH 检查
|
|
56
|
+
3. 各工具路径与关键配置
|
|
57
|
+
4. 端口占用
|
|
58
|
+
5. 全部跑一遍
|
|
59
|
+
0. 退出
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
非交互(管道 / CI):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
devcheck </dev/null
|
|
66
|
+
# 或
|
|
67
|
+
python checkdev.py </dev/null
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
建议在 PowerShell、Windows Terminal 等真正的终端里运行,颜色显示最完整。
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Overview
|
|
75
|
+
|
|
76
|
+
`dcheckdev` prints colored tables showing:
|
|
77
|
+
|
|
78
|
+
1. **Tool versions**: auto-detects installed tools from a built-in common catalog via `PATH` (`shutil.which`); shows version and executable path; skips missing catalog entries (does not scan every PATH executable)
|
|
79
|
+
2. **PATH check**: duplicate, missing, unexpanded-variable and file-instead-of-directory entries
|
|
80
|
+
3. **Key configs**: probes only for detected tools (Go env, pip/npm registry, Git identity, Docker Compose plugin, etc.); env vars such as `JAVA_HOME` appear when set or when a related tool is installed
|
|
81
|
+
4. **Port usage**: whether ports 8000, 8080, 5173, 3306, 5672 and 6379 are in use, and by which process
|
|
82
|
+
|
|
83
|
+
From **0.2.0**, in an interactive TTY `devcheck` shows a short opening animation and a numbered menu. Option 3 only lists config subgroups that have something to show (plus "all configs"). When stdin or stdout is not a TTY (CI, pipes), it falls back to running all checks once without prompting.
|
|
84
|
+
|
|
85
|
+
### Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python -m pip install dcheckdev
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Usage
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
devcheck
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dcheckdev"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "One-command local dev environment checker: tool versions, PATH, key configs and port usage"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
dcheckdev-0.1.0/PKG-INFO
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
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
|
dcheckdev-0.1.0/README.md
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# dcheckdev
|
|
2
|
-
|
|
3
|
-
一键检查本地开发环境的命令行工具。 / A one-command local dev environment checker.
|
|
4
|
-
|
|
5
|
-
## 简介
|
|
6
|
-
|
|
7
|
-
`dcheckdev` 会用彩色表格列出:
|
|
8
|
-
|
|
9
|
-
1. **工具版本**:Python、Go、Node、Git、Java、Wails 是否安装、版本号和实际使用的位置
|
|
10
|
-
2. **PATH 检查**:重复、失效、变量无法展开、误把文件写进 PATH 的条目
|
|
11
|
-
3. **关键配置**:GOROOT / GOPATH / GOPROXY、pip 镜像、npm 镜像和全局目录、Git 用户名和邮箱、JAVA_HOME
|
|
12
|
-
4. **端口占用**:8000、8080、5173、3306、5672、6379 是否被占用,以及占用的程序
|
|
13
|
-
|
|
14
|
-
### 安装
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
python -m pip install dcheckdev
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### 使用
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
devcheck
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
建议在 PowerShell、Windows Terminal 等真正的终端里运行,颜色显示最完整。
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Overview
|
|
31
|
-
|
|
32
|
-
`dcheckdev` prints colored tables showing:
|
|
33
|
-
|
|
34
|
-
1. **Tool versions**: whether Python, Go, Node, Git, Java and Wails are installed, their versions and which executable is actually used
|
|
35
|
-
2. **PATH check**: duplicate, missing, unexpanded-variable and file-instead-of-directory entries
|
|
36
|
-
3. **Key configs**: GOROOT / GOPATH / GOPROXY, pip index, npm registry and global prefix, Git user name and email, JAVA_HOME
|
|
37
|
-
4. **Port usage**: whether ports 8000, 8080, 5173, 3306, 5672 and 6379 are in use, and by which process
|
|
38
|
-
|
|
39
|
-
### Install
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
python -m pip install dcheckdev
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Usage
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
devcheck
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## License
|
|
52
|
-
|
|
53
|
-
MIT
|
dcheckdev-0.1.0/checkdev.py
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
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()
|
|
@@ -1,72 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|