Files
jianda-proxy/docs/superpowers/specs/2026-05-28-cli-tool-packaging-design.md
2026-05-28 17:59:24 +08:00

4.3 KiB
Raw Blame History

jianda-proxy CLI 工具打包设计

日期2026-05-28 状态:已批准

背景

jianda-proxy 是一个 HTTP 代理工具,用于解决腾讯云 ICP 拦截导致 Git LFS 下载失败的问题。目前是一个单文件 Python 脚本(lfs-proxy.py),配置硬编码,直接 python3 运行。

目标:将其打包为标准的 Python CLI 工具,支持 uvx 运行、uv tool install 安装、后台运行、CLI 管理生命周期且跨平台Windows + Mac

决策

  • 工具名称jianda-proxy
  • 配置格式INI标准库 configparser,零外部依赖)
  • 后台运行纯标准库Unix 用 os.fork()Windows 用 subprocess detached
  • 配置管理CLI config 子命令

项目结构

jianda-proxy/
├── pyproject.toml
├── src/
│   └── jianda_proxy/
│       ├── __init__.py
│       ├── cli.py          # CLI 入口argparse 子命令
│       ├── proxy.py        # 代理逻辑
│       ├── config.py       # INI 配置管理
│       └── daemon.py       # 跨平台后台运行管理
├── docs/
│   └── superpowers/specs/
└── README.md

pyproject.toml

  • 零外部依赖
  • Python >= 3.8
  • 入口点:jianda-proxy = "jianda_proxy.cli:main"
  • 构建后端:hatchling

打包与分发

  • uv tool install .:本地安装
  • uvx jianda-proxy:临时运行(需发布到 PyPI 后)
  • python -m jianda_proxy:作为模块运行

配置管理

配置文件位置

  • Mac/Linux~/.config/jianda-proxy/config.ini
  • Windows%APPDATA%\jianda-proxy\config.ini

通过 os.path.expanduseros.environ 手动拼路径,不引入 platformdirs

配置格式

[proxy]
remote_domain = git.zz.com
upstream_host = 62.234.191.215
upstream_port = 3000
listen_port = 13000
listen_host = 127.0.0.1

config 子命令

命令 说明
config set <key> <value> 设置配置项
config get <key> 查看单个配置项
config list 列出所有配置
config path 显示配置文件路径

首次使用 start 时,如果配置文件不存在,用默认值自动创建。

CLI 命令

jianda-proxy start [--port PORT] [--foreground]
jianda-proxy stop
jianda-proxy status
jianda-proxy config set <key> <value>
jianda-proxy config get <key>
jianda-proxy config list
jianda-proxy config path

start --foreground:前台运行,日志直接输出到终端,方便调试。

后台运行与生命周期

start

  1. 检查端口是否可用
  2. 检查是否已有进程运行PID 文件存在且进程存活)
  3. 如果已有进程:提示错误并退出
  4. 如果 PID 文件存在但进程已死:清理后继续
  5. Unixos.fork() 后父进程退出
  6. Windowssubprocess.Popen with CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS
  7. 写 PID 文件
  8. 日志写到 ~/.config/jianda-proxy/proxy.logRotatingFileHandler5MB3 个备份)

stop

  1. 读取 PID 文件
  2. 检查进程是否存在
  3. 发送 SIGTERMUnix/ taskkillWindows
  4. 等待最多 3 秒
  5. 如果还活着SIGKILL / 强制终止
  6. 删除 PID 文件

status

  1. 读取 PID 文件
  2. 检查进程是否存在
  3. 显示运行状态、PID、端口、运行时间

PID 文件

位置:和配置文件同目录 ~/.config/jianda-proxy/daemon.pid

跨平台细节

操作 Unix Windows
后台启动 os.fork() subprocess.Popen + detached flags
进程检查 os.kill(pid, 0) ctypes 调用 kernel32.OpenProcess + GetExitCodeProcess
优雅停止 SIGTERM taskkill /PID
强制停止 SIGKILL taskkill /F /PID
配置目录 ~/.config/ %APPDATA%

错误处理

  • 端口被占用:提示具体端口和可能原因
  • 配置无效IP 格式错误等):启动前验证
  • 权限不足:提示需要的权限
  • 后台进程异常退出:status 检测到后提示查看日志

模块职责

  • cli.pyargparse 定义、子命令分发、入口函数
  • config.py:读写配置文件、默认值管理、配置路径计算
  • proxy.pyHTTP 代理服务器逻辑(从现有 lfs-proxy.py 提取)
  • daemon.pyPID 文件管理、跨平台进程检查、进程终止