555 lines
12 KiB
Markdown
555 lines
12 KiB
Markdown
|
|
# 入口脚本设计
|
|||
|
|
|
|||
|
|
## 一、概述
|
|||
|
|
|
|||
|
|
### 1.1 设计目标
|
|||
|
|
|
|||
|
|
提供跨平台的统一命令行入口,使用户可以通过 `aide <command>` 的方式调用所有功能。
|
|||
|
|
|
|||
|
|
### 1.2 入口脚本清单
|
|||
|
|
|
|||
|
|
| 脚本 | 平台 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| `aide.sh` | Linux/macOS | Shell 脚本入口 |
|
|||
|
|
| `aide.bat` | Windows | 批处理脚本入口 |
|
|||
|
|
| `main.py` | 所有平台 | Python 主程序 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、aide.sh 设计(Linux/macOS)
|
|||
|
|
|
|||
|
|
### 2.1 功能要求
|
|||
|
|
|
|||
|
|
1. **定位 Python**:查找可用的 Python 3.10+ 解释器
|
|||
|
|
2. **定位脚本目录**:确定 main.py 的位置
|
|||
|
|
3. **传递参数**:将所有命令行参数传递给 Python 程序
|
|||
|
|
4. **处理错误**:Python 未找到时给出明确提示
|
|||
|
|
|
|||
|
|
### 2.2 实现示例
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
#!/usr/bin/env bash
|
|||
|
|
# Aide 命令行工具入口脚本(Linux/macOS)
|
|||
|
|
# 版本: 1.0
|
|||
|
|
|
|||
|
|
set -e # 遇到错误立即退出
|
|||
|
|
|
|||
|
|
# 获取脚本所在目录
|
|||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
|
|
|
|||
|
|
# Python 主程序路径
|
|||
|
|
MAIN_PY="${SCRIPT_DIR}/main.py"
|
|||
|
|
|
|||
|
|
# 查找 Python 解释器
|
|||
|
|
find_python() {
|
|||
|
|
# 尝试查找 Python 3.10+
|
|||
|
|
for cmd in python3.12 python3.11 python3.10 python3 python; do
|
|||
|
|
if command -v "$cmd" &> /dev/null; then
|
|||
|
|
# 检查版本
|
|||
|
|
version=$("$cmd" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
|||
|
|
major=$(echo "$version" | cut -d. -f1)
|
|||
|
|
minor=$(echo "$version" | cut -d. -f2)
|
|||
|
|
|
|||
|
|
if [ "$major" -eq 3 ] && [ "$minor" -ge 10 ]; then
|
|||
|
|
echo "$cmd"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
return 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 查找 Python
|
|||
|
|
PYTHON=$(find_python)
|
|||
|
|
|
|||
|
|
if [ -z "$PYTHON" ]; then
|
|||
|
|
echo "✗ Python 3.10+ 未找到" >&2
|
|||
|
|
echo " 建议: 安装 Python 3.10 或更高版本" >&2
|
|||
|
|
echo " 文档: https://www.python.org/downloads/" >&2
|
|||
|
|
exit 3
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# 检查 main.py 是否存在
|
|||
|
|
if [ ! -f "$MAIN_PY" ]; then
|
|||
|
|
echo "✗ 找不到 main.py" >&2
|
|||
|
|
echo " 位置: $MAIN_PY" >&2
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# 执行 Python 程序
|
|||
|
|
exec "$PYTHON" "$MAIN_PY" "$@"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.3 安装方式
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 方式1:添加到 PATH
|
|||
|
|
export PATH="/path/to/aide:$PATH"
|
|||
|
|
|
|||
|
|
# 方式2:创建符号链接
|
|||
|
|
ln -s /path/to/aide/aide.sh /usr/local/bin/aide
|
|||
|
|
|
|||
|
|
# 方式3:添加别名
|
|||
|
|
alias aide='/path/to/aide/aide.sh'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、aide.bat 设计(Windows)
|
|||
|
|
|
|||
|
|
### 3.1 功能要求
|
|||
|
|
|
|||
|
|
1. **定位 Python**:查找可用的 Python 3.10+ 解释器
|
|||
|
|
2. **定位脚本目录**:确定 main.py 的位置
|
|||
|
|
3. **传递参数**:将所有命令行参数传递给 Python 程序
|
|||
|
|
4. **处理错误**:Python 未找到时给出明确提示
|
|||
|
|
|
|||
|
|
### 3.2 实现示例
|
|||
|
|
|
|||
|
|
```batch
|
|||
|
|
@echo off
|
|||
|
|
REM Aide 命令行工具入口脚本(Windows)
|
|||
|
|
REM 版本: 1.0
|
|||
|
|
|
|||
|
|
setlocal enabledelayedexpansion
|
|||
|
|
|
|||
|
|
REM 获取脚本所在目录
|
|||
|
|
set "SCRIPT_DIR=%~dp0"
|
|||
|
|
|
|||
|
|
REM Python 主程序路径
|
|||
|
|
set "MAIN_PY=%SCRIPT_DIR%main.py"
|
|||
|
|
|
|||
|
|
REM 查找 Python 解释器
|
|||
|
|
set "PYTHON="
|
|||
|
|
for %%p in (python3.12 python3.11 python3.10 python3 python py) do (
|
|||
|
|
where %%p >nul 2>&1
|
|||
|
|
if !errorlevel! equ 0 (
|
|||
|
|
REM 检查版本
|
|||
|
|
for /f "delims=" %%v in ('%%p -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"') do (
|
|||
|
|
set "version=%%v"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
REM 解析版本号
|
|||
|
|
for /f "tokens=1,2 delims=." %%a in ("!version!") do (
|
|||
|
|
set "major=%%a"
|
|||
|
|
set "minor=%%b"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
REM 检查是否满足要求(3.10+)
|
|||
|
|
if !major! equ 3 if !minor! geq 10 (
|
|||
|
|
set "PYTHON=%%p"
|
|||
|
|
goto :found
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
:found
|
|||
|
|
if "%PYTHON%"=="" (
|
|||
|
|
echo ✗ Python 3.10+ 未找到 >&2
|
|||
|
|
echo 建议: 安装 Python 3.10 或更高版本 >&2
|
|||
|
|
echo 文档: https://www.python.org/downloads/ >&2
|
|||
|
|
exit /b 3
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
REM 检查 main.py 是否存在
|
|||
|
|
if not exist "%MAIN_PY%" (
|
|||
|
|
echo ✗ 找不到 main.py >&2
|
|||
|
|
echo 位置: %MAIN_PY% >&2
|
|||
|
|
exit /b 1
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
REM 执行 Python 程序
|
|||
|
|
"%PYTHON%" "%MAIN_PY%" %*
|
|||
|
|
exit /b %errorlevel%
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 安装方式
|
|||
|
|
|
|||
|
|
```batch
|
|||
|
|
REM 方式1:添加到 PATH
|
|||
|
|
set PATH=C:\path\to\aide;%PATH%
|
|||
|
|
|
|||
|
|
REM 方式2:创建批处理文件到系统目录
|
|||
|
|
copy aide.bat C:\Windows\System32\aide.bat
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、main.py 设计
|
|||
|
|
|
|||
|
|
### 4.1 功能要求
|
|||
|
|
|
|||
|
|
1. **命令分发**:根据第一个参数分发到对应的命令处理函数
|
|||
|
|
2. **参数解析**:解析命令行参数
|
|||
|
|
3. **错误处理**:统一的错误处理和退出码
|
|||
|
|
4. **帮助信息**:提供 `--help` 和 `--version` 支持
|
|||
|
|
|
|||
|
|
### 4.2 实现框架
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
Aide 命令行工具主程序
|
|||
|
|
版本: 1.0
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# 添加 src 目录到 Python 路径
|
|||
|
|
SCRIPT_DIR = Path(__file__).parent
|
|||
|
|
sys.path.insert(0, str(SCRIPT_DIR))
|
|||
|
|
|
|||
|
|
from core.output import ok, warn, err, info
|
|||
|
|
from commands.init import cmd_init
|
|||
|
|
from commands.env import cmd_env
|
|||
|
|
from commands.config_cmd import cmd_config
|
|||
|
|
|
|||
|
|
|
|||
|
|
VERSION = "1.0.0"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def show_help():
|
|||
|
|
"""显示帮助信息"""
|
|||
|
|
help_text = """Aide - AI 辅助开发工作流工具
|
|||
|
|
|
|||
|
|
用法:
|
|||
|
|
aide <command> [options]
|
|||
|
|
|
|||
|
|
命令:
|
|||
|
|
init 初始化 .aide 目录和配置文件
|
|||
|
|
env ensure 检测并修复项目开发环境
|
|||
|
|
env ensure --runtime 检测 aide 运行时环境
|
|||
|
|
config get <key> 获取配置值
|
|||
|
|
config set <key> <value> 设置配置值
|
|||
|
|
|
|||
|
|
选项:
|
|||
|
|
-h, --help 显示帮助信息
|
|||
|
|
-v, --version 显示版本信息
|
|||
|
|
|
|||
|
|
示例:
|
|||
|
|
aide init
|
|||
|
|
aide env ensure
|
|||
|
|
aide config get task.source
|
|||
|
|
aide config set task.source "new-task.md"
|
|||
|
|
|
|||
|
|
文档: https://github.com/your-org/aide
|
|||
|
|
"""
|
|||
|
|
print(help_text)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def show_version():
|
|||
|
|
"""显示版本信息"""
|
|||
|
|
print(f"Aide v{VERSION}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
# 解析参数
|
|||
|
|
args = sys.argv[1:]
|
|||
|
|
|
|||
|
|
# 无参数或帮助
|
|||
|
|
if not args or args[0] in ["-h", "--help", "help"]:
|
|||
|
|
show_help()
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
# 版本信息
|
|||
|
|
if args[0] in ["-v", "--version", "version"]:
|
|||
|
|
show_version()
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
# 获取命令
|
|||
|
|
command = args[0]
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 命令分发
|
|||
|
|
if command == "init":
|
|||
|
|
return cmd_init(args[1:])
|
|||
|
|
elif command == "env":
|
|||
|
|
return cmd_env(args[1:])
|
|||
|
|
elif command == "config":
|
|||
|
|
return cmd_config(args[1:])
|
|||
|
|
else:
|
|||
|
|
err(
|
|||
|
|
f"未知命令: {command}",
|
|||
|
|
[
|
|||
|
|
"可用命令: init, env, config",
|
|||
|
|
"使用 'aide --help' 查看帮助"
|
|||
|
|
]
|
|||
|
|
)
|
|||
|
|
return 2
|
|||
|
|
|
|||
|
|
except KeyboardInterrupt:
|
|||
|
|
print("\n")
|
|||
|
|
info("操作已取消")
|
|||
|
|
return 130 # 128 + SIGINT(2)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
err(
|
|||
|
|
"命令执行失败",
|
|||
|
|
[
|
|||
|
|
f"原因: {str(e)}",
|
|||
|
|
"使用 'aide --help' 查看帮助"
|
|||
|
|
]
|
|||
|
|
)
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
sys.exit(main())
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 命令处理函数接口
|
|||
|
|
|
|||
|
|
每个命令处理函数应该遵循以下接口:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def cmd_<command>(args: list[str]) -> int:
|
|||
|
|
"""命令处理函数
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
args: 命令参数列表(不包含命令本身)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
退出码(0 表示成功)
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、参数解析
|
|||
|
|
|
|||
|
|
### 5.1 简单参数解析
|
|||
|
|
|
|||
|
|
对于简单的命令,可以手动解析参数:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def cmd_env(args: list[str]) -> int:
|
|||
|
|
"""env 命令处理"""
|
|||
|
|
if not args:
|
|||
|
|
err("缺少子命令", ["使用 'aide env ensure' 检测环境"])
|
|||
|
|
return 2
|
|||
|
|
|
|||
|
|
subcommand = args[0]
|
|||
|
|
|
|||
|
|
if subcommand == "ensure":
|
|||
|
|
# 检查 --runtime 参数
|
|||
|
|
runtime_only = "--runtime" in args
|
|||
|
|
return env_ensure(runtime_only=runtime_only)
|
|||
|
|
else:
|
|||
|
|
err(f"未知子命令: {subcommand}", ["可用子命令: ensure"])
|
|||
|
|
return 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 使用 argparse(可选)
|
|||
|
|
|
|||
|
|
对于复杂的命令,可以使用 argparse:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import argparse
|
|||
|
|
|
|||
|
|
def cmd_config(args: list[str]) -> int:
|
|||
|
|
"""config 命令处理"""
|
|||
|
|
parser = argparse.ArgumentParser(
|
|||
|
|
prog="aide config",
|
|||
|
|
description="配置管理"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
subparsers = parser.add_subparsers(dest="subcommand")
|
|||
|
|
|
|||
|
|
# get 子命令
|
|||
|
|
parser_get = subparsers.add_parser("get", help="获取配置值")
|
|||
|
|
parser_get.add_argument("key", help="配置键")
|
|||
|
|
|
|||
|
|
# set 子命令
|
|||
|
|
parser_set = subparsers.add_parser("set", help="设置配置值")
|
|||
|
|
parser_set.add_argument("key", help="配置键")
|
|||
|
|
parser_set.add_argument("value", help="配置值")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
parsed = parser.parse_args(args)
|
|||
|
|
except SystemExit:
|
|||
|
|
return 2
|
|||
|
|
|
|||
|
|
if parsed.subcommand == "get":
|
|||
|
|
return config_get(parsed.key)
|
|||
|
|
elif parsed.subcommand == "set":
|
|||
|
|
return config_set(parsed.key, parsed.value)
|
|||
|
|
else:
|
|||
|
|
parser.print_help()
|
|||
|
|
return 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、错误处理
|
|||
|
|
|
|||
|
|
### 6.1 异常捕获
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
try:
|
|||
|
|
# 命令执行
|
|||
|
|
return execute_command()
|
|||
|
|
|
|||
|
|
except KeyboardInterrupt:
|
|||
|
|
# Ctrl+C 中断
|
|||
|
|
print("\n")
|
|||
|
|
info("操作已取消")
|
|||
|
|
return 130
|
|||
|
|
|
|||
|
|
except FileNotFoundError as e:
|
|||
|
|
# 文件不存在
|
|||
|
|
err("文件不存在", [f"路径: {e.filename}"])
|
|||
|
|
return 5
|
|||
|
|
|
|||
|
|
except PermissionError as e:
|
|||
|
|
# 权限错误
|
|||
|
|
err("权限不足", [f"路径: {e.filename}"])
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
# 其他错误
|
|||
|
|
err("命令执行失败", [f"原因: {str(e)}"])
|
|||
|
|
return 1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 退出码规范
|
|||
|
|
|
|||
|
|
| 退出码 | 含义 |
|
|||
|
|
|-------|------|
|
|||
|
|
| 0 | 成功 |
|
|||
|
|
| 1 | 一般错误 |
|
|||
|
|
| 2 | 参数错误 |
|
|||
|
|
| 3 | 环境错误 |
|
|||
|
|
| 4 | 配置错误 |
|
|||
|
|
| 5 | 文件错误 |
|
|||
|
|
| 130 | 用户中断(Ctrl+C) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、测试
|
|||
|
|
|
|||
|
|
### 7.1 入口脚本测试
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 测试 aide.sh
|
|||
|
|
./aide.sh --version
|
|||
|
|
./aide.sh --help
|
|||
|
|
./aide.sh init
|
|||
|
|
./aide.sh env ensure
|
|||
|
|
|
|||
|
|
# 测试 aide.bat(Windows)
|
|||
|
|
aide.bat --version
|
|||
|
|
aide.bat --help
|
|||
|
|
aide.bat init
|
|||
|
|
aide.bat env ensure
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 main.py 测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def test_main_help(capsys):
|
|||
|
|
"""测试帮助信息"""
|
|||
|
|
sys.argv = ["aide", "--help"]
|
|||
|
|
result = main()
|
|||
|
|
|
|||
|
|
assert result == 0
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "用法:" in captured.out
|
|||
|
|
|
|||
|
|
def test_main_version(capsys):
|
|||
|
|
"""测试版本信息"""
|
|||
|
|
sys.argv = ["aide", "--version"]
|
|||
|
|
result = main()
|
|||
|
|
|
|||
|
|
assert result == 0
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "Aide v" in captured.out
|
|||
|
|
|
|||
|
|
def test_main_unknown_command(capsys):
|
|||
|
|
"""测试未知命令"""
|
|||
|
|
sys.argv = ["aide", "unknown"]
|
|||
|
|
result = main()
|
|||
|
|
|
|||
|
|
assert result == 2
|
|||
|
|
captured = capsys.readouterr()
|
|||
|
|
assert "未知命令" in captured.out
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、安装和分发
|
|||
|
|
|
|||
|
|
### 8.1 目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
aide/
|
|||
|
|
├── aide.sh # Linux/macOS 入口
|
|||
|
|
├── aide.bat # Windows 入口
|
|||
|
|
├── main.py # Python 主程序
|
|||
|
|
├── core/ # 核心模块
|
|||
|
|
├── commands/ # 命令实现
|
|||
|
|
└── utils/ # 工具函数
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.2 安装脚本(可选)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
#!/usr/bin/env bash
|
|||
|
|
# install.sh - Aide 安装脚本
|
|||
|
|
|
|||
|
|
set -e
|
|||
|
|
|
|||
|
|
INSTALL_DIR="${HOME}/.local/bin"
|
|||
|
|
|
|||
|
|
# 创建安装目录
|
|||
|
|
mkdir -p "$INSTALL_DIR"
|
|||
|
|
|
|||
|
|
# 复制文件
|
|||
|
|
cp -r aide "$INSTALL_DIR/"
|
|||
|
|
|
|||
|
|
# 创建符号链接
|
|||
|
|
ln -sf "$INSTALL_DIR/aide/aide.sh" "$INSTALL_DIR/aide"
|
|||
|
|
|
|||
|
|
# 添加到 PATH
|
|||
|
|
if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
|
|||
|
|
echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> ~/.bashrc
|
|||
|
|
echo "✓ 已添加到 PATH"
|
|||
|
|
echo " 请运行: source ~/.bashrc"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo "✓ Aide 安装完成"
|
|||
|
|
echo " 使用 'aide --help' 查看帮助"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 九、总结
|
|||
|
|
|
|||
|
|
### 9.1 核心要点
|
|||
|
|
|
|||
|
|
1. 提供跨平台的统一入口
|
|||
|
|
2. 自动查找合适的 Python 解释器
|
|||
|
|
3. 统一的命令分发和错误处理
|
|||
|
|
4. 清晰的帮助和版本信息
|
|||
|
|
|
|||
|
|
### 9.2 实现检查清单
|
|||
|
|
|
|||
|
|
- [ ] 实现 aide.sh(Linux/macOS)
|
|||
|
|
- [ ] 实现 aide.bat(Windows)
|
|||
|
|
- [ ] 实现 main.py 命令分发
|
|||
|
|
- [ ] 实现帮助和版本信息
|
|||
|
|
- [ ] 实现错误处理和退出码
|
|||
|
|
- [ ] 编写入口脚本测试
|
|||
|
|
- [ ] 验证跨平台兼容性
|
|||
|
|
- [ ] 编写安装脚本(可选)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**版本**:v1.0
|
|||
|
|
**更新日期**:2025-12-13
|