This commit is contained in:
zyj
2026-03-03 18:20:18 +08:00
commit a9f9330744
25 changed files with 5004 additions and 0 deletions

638
docs/DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,638 @@
# DevPack 开发指南
> 版本v1.0.0-draft
> 更新日期2026-03-03
> 作者DevPack Team
---
## 1. 开发环境搭建
### 1.1 前置要求
| 工具 | 最低版本 | 安装方式 |
|------|---------|---------|
| Go | 1.22+ | [golang.org](https://golang.org/dl/) |
| Git | 2.30+ | [git-scm.com](https://git-scm.com/) |
| Make | 3.81+ | 系统包管理器Windows 推荐用 `choco install make` |
| golangci-lint | 1.55+ | `go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest` |
### 1.2 获取代码
```bash
git clone https://github.com/user/devpack.git
cd devpack
```
### 1.3 安装依赖
```bash
go mod download
```
### 1.4 验证环境
```bash
# 运行测试
go test ./...
# 构建
go build -o devpack ./cmd/devpack/
# 代码检查
golangci-lint run
```
---
## 2. 项目结构详解
```
DevPack/
├── cmd/ # 应用入口
│ └── devpack/
│ ├── main.go # 主入口
│ └── commands/ # CLI 命令
│ ├── root.go # 根命令
│ ├── init.go # devpack init
│ ├── scan.go # devpack scan
│ ├── capture.go # devpack capture
│ ├── restore.go # devpack restore
│ ├── diff.go # devpack diff
│ ├── export.go # devpack export
│ ├── import.go # devpack import
│ ├── list.go # devpack list
│ ├── profile.go # devpack profile
│ └── version.go # devpack version
├── internal/ # 内部包
│ ├── collector/ # 采集器核心
│ │ ├── collector.go # Collector 接口定义
│ │ ├── registry.go # 采集器注册中心
│ │ ├── options.go # 扫描/捕获/还原选项
│ │ ├── result.go # 结果类型定义
│ │ │
│ │ ├── runtime/ # 运行时采集器
│ │ │ ├── go.go # Go 采集器
│ │ │ ├── node.go # Node.js 采集器
│ │ │ ├── python.go # Python 采集器
│ │ │ ├── java.go # Java 采集器
│ │ │ ├── rust.go # Rust 采集器
│ │ │ ├── dotnet.go # .NET 采集器
│ │ │ └── runtime_test.go # 运行时采集器测试
│ │ │
│ │ ├── editor/ # 编辑器采集器
│ │ │ ├── vscode.go # VS Code 采集器
│ │ │ ├── jetbrains.go # JetBrains 采集器
│ │ │ ├── vim.go # Vim/Neovim 采集器
│ │ │ └── editor_test.go
│ │ │
│ │ ├── shell/ # Shell 采集器
│ │ │ ├── powershell.go # PowerShell 采集器
│ │ │ ├── bash.go # Bash 采集器
│ │ │ ├── zsh.go # Zsh 采集器
│ │ │ ├── fish.go # Fish 采集器
│ │ │ ├── terminal.go # 终端模拟器配置Windows Terminal 等)
│ │ │ └── shell_test.go
│ │ │
│ │ ├── pkgmgr/ # 包管理器采集器
│ │ │ ├── scoop.go # Scoop 采集器
│ │ │ ├── chocolatey.go # Chocolatey 采集器
│ │ │ ├── winget.go # Winget 采集器
│ │ │ ├── homebrew.go # Homebrew 采集器
│ │ │ ├── apt.go # APT 采集器
│ │ │ └── pkgmgr_test.go
│ │ │
│ │ ├── git/ # Git 配置采集器
│ │ │ ├── gitconfig.go
│ │ │ └── git_test.go
│ │ │
│ │ ├── env/ # 环境变量采集器
│ │ │ ├── envvar.go
│ │ │ └── env_test.go
│ │ │
│ │ ├── font/ # 字体采集器
│ │ │ ├── font.go
│ │ │ └── font_test.go
│ │ │
│ │ └── ssh/ # SSH/GPG 采集器
│ │ ├── ssh.go
│ │ └── ssh_test.go
│ │
│ ├── pack/ # 打包引擎
│ │ ├── packer.go # 打包器
│ │ ├── unpacker.go # 解包器
│ │ ├── format.go # Pack 格式定义
│ │ └── pack_test.go
│ │
│ ├── restore/ # 还原引擎
│ │ ├── engine.go # 还原核心逻辑
│ │ ├── planner.go # 还原计划生成
│ │ ├── conflict.go # 冲突检测与处理
│ │ ├── rollback.go # 回滚管理
│ │ ├── verifier.go # 还原验证
│ │ └── restore_test.go
│ │
│ ├── profile/ # 配置文件管理
│ │ ├── profile.go # Profile 定义与操作
│ │ ├── parser.go # YAML 解析
│ │ └── profile_test.go
│ │
│ ├── diff/ # 差异对比
│ │ ├── differ.go # 差异计算
│ │ ├── renderer.go # 差异展示
│ │ └── diff_test.go
│ │
│ ├── crypto/ # 加密模块
│ │ ├── aesgcm.go # AES-256-GCM 实现
│ │ ├── argon2.go # Argon2id 密钥派生
│ │ └── crypto_test.go
│ │
│ ├── platform/ # 平台适配层
│ │ ├── platform.go # Platform 接口
│ │ ├── detect.go # 平台检测
│ │ ├── windows.go # Windows 实现
│ │ ├── darwin.go # macOS 实现
│ │ ├── linux.go # Linux 实现
│ │ └── platform_test.go
│ │
│ ├── config/ # 应用配置
│ │ ├── config.go # 全局配置
│ │ └── paths.go # 路径管理
│ │
│ ├── ui/ # 终端 UI
│ │ ├── printer.go # 格式化输出
│ │ ├── progress.go # 进度条
│ │ ├── table.go # 表格输出
│ │ └── prompt.go # 用户交互
│ │
│ └── logger/ # 日志
│ └── logger.go # 日志初始化
├── pkg/ # 公共包
│ ├── manifest/ # Pack 清单
│ │ ├── manifest.go # Manifest 结构定义
│ │ └── validate.go # Manifest 验证
│ └── version/ # 版本信息
│ └── version.go # 版本号管理
├── plugins/ # 外部插件目录
│ └── README.md # 插件开发指南
├── test/ # 集成与端到端测试
│ ├── e2e/ # 端到端测试
│ │ ├── capture_restore_test.go
│ │ └── testdata/ # 测试数据
│ └── fixtures/ # 测试 fixtures
│ └── sample-pack/
├── scripts/ # 脚本
│ ├── build.sh # 构建脚本
│ ├── install.sh # 安装脚本
│ └── release.sh # 发布脚本
├── .github/
│ └── workflows/
│ ├── ci.yml # CI 流水线
│ └── release.yml # 发布流水线
├── .golangci.yml # Lint 配置
├── .gitignore
├── go.mod
├── go.sum
├── Makefile
├── LICENSE
└── README.md
```
---
## 3. 编码规范
### 3.1 Go 编码规范
遵循 [Effective Go](https://golang.org/doc/effective_go) 和 [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)。
#### 命名规范
```go
// ✅ 包名:小写单词,不用下划线
package collector
package pkgmgr
// ✅ 接口名:动词或名词,单方法接口用 -er 后缀
type Collector interface { ... }
type Scanner interface { ... }
// ✅ 导出函数/方法:大驼峰
func NewRegistry() *Registry { ... }
func (r *Registry) Register(c Collector) error { ... }
// ✅ 非导出函数/方法:小驼峰
func parseVersion(raw string) (string, error) { ... }
// ✅ 常量:大驼峰(导出)或小驼峰(非导出)
const DefaultTimeout = 30 * time.Second
const maxRetries = 3
// ✅ 错误变量Err 前缀
var ErrCollectorNotFound = errors.New("collector not found")
var ErrPackCorrupted = errors.New("pack file corrupted")
```
#### 错误处理
```go
// ✅ 使用 fmt.Errorf 包装错误,提供上下文
func (c *GoCollector) Scan(ctx context.Context) (*ScanResult, error) {
version, err := c.detectVersion(ctx)
if err != nil {
return nil, fmt.Errorf("go collector: detect version: %w", err)
}
// ...
}
// ✅ 自定义错误类型用于需要类型判断的场景
type CollectorError struct {
Collector string
Op string
Err error
}
func (e *CollectorError) Error() string {
return fmt.Sprintf("%s: %s: %v", e.Collector, e.Op, e.Err)
}
func (e *CollectorError) Unwrap() error {
return e.Err
}
```
#### Context 使用
```go
// ✅ 第一个参数传递 context
func (c *GoCollector) Scan(ctx context.Context, opts ScanOptions) (*ScanResult, error) {
// 使用 context 控制超时
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "go", "version")
// ...
}
```
### 3.2 项目约定
| 约定 | 说明 |
|------|------|
| 文件命名 | 小写 + 下划线:`go_collector.go`, `scan_result.go` |
| 测试文件 | `*_test.go` 放在同一包下 |
| 平台特定 | 使用 Go build tag`//go:build windows` |
| 依赖注入 | 通过接口 + 构造函数实现 |
| 配置 | 使用 Viper支持文件 + 环境变量 + 命令行参数 |
| 日志 | 使用 zerolog结构化日志 |
### 3.3 Git 提交规范
使用 [Conventional Commits](https://www.conventionalcommits.org/)
```
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
```
**类型 (type)**
| Type | 说明 |
|------|------|
| `feat` | 新功能 |
| `fix` | Bug 修复 |
| `docs` | 文档 |
| `style` | 代码格式 |
| `refactor` | 重构 |
| `perf` | 性能优化 |
| `test` | 测试 |
| `chore` | 构建/工具 |
**Scope 示例:** `collector`, `pack`, `restore`, `cli`, `platform`, `crypto`
**示例:**
```
feat(collector): add VS Code extension collector
Scan and capture VS Code extensions list and settings.
Closes #42
```
---
## 4. 开发工作流
### 4.1 分支策略
```
main (稳定发布)
├── develop (开发主干)
│ │
│ ├── feature/collector-vscode (功能分支)
│ ├── feature/restore-engine (功能分支)
│ └── fix/scan-timeout (修复分支)
└── release/v0.1.0 (发布分支)
```
### 4.2 开发流程
1. **创建分支:** `git checkout -b feature/xxx develop`
2. **开发 & 测试:** 编写代码 + 单元测试
3. **代码检查:** `make lint`
4. **提交:** 遵循 Conventional Commits
5. **推送 & PR** 推送分支,创建 Pull Request
6. **Code Review** 至少一人 Review 通过
7. **合并:** Squash Merge 到 develop
### 4.3 常用 Make 命令
```makefile
# 构建
make build # 构建当前平台
make build-all # 构建所有平台
make build-windows # 构建 Windows 版本
make build-darwin # 构建 macOS 版本
make build-linux # 构建 Linux 版本
# 测试
make test # 运行所有测试
make test-unit # 运行单元测试
make test-integration # 运行集成测试
make test-e2e # 运行端到端测试
make test-coverage # 生成覆盖率报告
# 代码质量
make lint # 运行 golangci-lint
make fmt # 格式化代码
make vet # go vet 检查
# 开发
make run # 编译并运行
make dev # 开发模式(热重载)
make clean # 清理构建产物
# 发布
make release # 使用 GoReleaser 发布
make snapshot # GoReleaser 快照(不发布)
```
---
## 5. 添加新采集器指南
### 5.1 步骤
以添加 "Docker" 采集器为例:
#### Step 1: 创建采集器文件
```go
// internal/collector/runtime/docker.go
package runtime
import (
"context"
"github.com/user/devpack/internal/collector"
)
// DockerCollector Docker 环境采集器
type DockerCollector struct{}
// 确保实现了 Collector 接口
var _ collector.Collector = (*DockerCollector)(nil)
func NewDockerCollector() *DockerCollector {
return &DockerCollector{}
}
func (c *DockerCollector) Name() string { return "docker" }
func (c *DockerCollector) DisplayName() string { return "Docker" }
func (c *DockerCollector) Description() string {
return "Captures Docker version, images, and configuration"
}
func (c *DockerCollector) Category() collector.Category {
return collector.CategoryRuntime
}
func (c *DockerCollector) IsAvailable(ctx context.Context) bool {
_, err := exec.LookPath("docker")
return err == nil
}
func (c *DockerCollector) Scan(ctx context.Context, opts collector.ScanOptions) (*collector.ScanResult, error) {
// 实现扫描逻辑
// 1. 检测 Docker 版本
// 2. 列出本地镜像
// 3. 获取 Docker daemon 配置
return nil, nil
}
func (c *DockerCollector) Capture(ctx context.Context, targetDir string, opts collector.CaptureOptions) error {
// 实现捕获逻辑
return nil
}
func (c *DockerCollector) Restore(ctx context.Context, sourceDir string, opts collector.RestoreOptions) error {
// 实现还原逻辑
return nil
}
func (c *DockerCollector) Verify(ctx context.Context) (*collector.VerifyResult, error) {
// 实现验证逻辑
return nil, nil
}
```
#### Step 2: 注册采集器
```go
// internal/collector/registry.go 中添加注册
func NewDefaultRegistry() *Registry {
r := NewRegistry()
// Runtime collectors
r.Register(runtime.NewGoCollector())
r.Register(runtime.NewNodeCollector())
r.Register(runtime.NewDockerCollector()) // 新增
// ...
return r
}
```
#### Step 3: 编写测试
```go
// internal/collector/runtime/docker_test.go
func TestDockerCollector_Scan(t *testing.T) {
c := NewDockerCollector()
if !c.IsAvailable(context.Background()) {
t.Skip("Docker not available")
}
result, err := c.Scan(context.Background(), collector.ScanOptions{})
assert.NoError(t, err)
assert.NotEmpty(t, result.Items)
}
```
#### Step 4: 更新文档
在 README.md 和 PRD.md 中添加 Docker 采集器的说明。
---
## 6. 调试指南
### 6.1 日志级别
```bash
# 设置日志级别
DEVPACK_LOG_LEVEL=debug devpack scan
# 或通过命令行参数
devpack scan --log-level debug
```
| 级别 | 用途 |
|------|------|
| `trace` | 非常详细的调试信息 |
| `debug` | 调试信息 |
| `info` | 正常操作信息(默认) |
| `warn` | 警告 |
| `error` | 错误 |
| `fatal` | 致命错误 |
### 6.2 VS Code 调试配置
```json
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug DevPack Scan",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/devpack",
"args": ["scan", "--verbose"],
"env": {
"DEVPACK_LOG_LEVEL": "debug"
}
},
{
"name": "Debug DevPack Capture",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/devpack",
"args": ["capture", "--name", "test-env"],
"env": {
"DEVPACK_LOG_LEVEL": "debug"
}
}
]
}
```
### 6.3 常见问题排查
| 问题 | 排查方向 |
|------|---------|
| 采集器找不到工具 | 检查 PATH 环境变量,确认工具已安装 |
| Pack 文件损坏 | 使用 `devpack verify <pack>` 校验 |
| 还原权限不足 | 以管理员身份运行 |
| 跨版本不兼容 | 检查 Manifest 中的 format_ver |
---
## 7. 发布流程
### 7.1 版本号规范
遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)
```
MAJOR.MINOR.PATCH[-PRERELEASE]
- MAJOR: 不兼容的 API 变更
- MINOR: 向下兼容的功能新增
- PATCH: 向下兼容的 Bug 修复
```
### 7.2 发布步骤
```bash
# 1. 确保所有测试通过
make test
# 2. 更新 CHANGELOG
# 编辑 CHANGELOG.md
# 3. 创建 Release Tag
git tag -a v0.1.0 -m "Release v0.1.0"
git push origin v0.1.0
# 4. GoReleaser 自动构建发布CI 触发)
# 或手动:
make release
```
### 7.3 GoReleaser 配置
```yaml
# .goreleaser.yml
version: 2
builds:
- main: ./cmd/devpack
binary: devpack
env:
- CGO_ENABLED=0
goos:
- windows
- darwin
- linux
goarch:
- amd64
- arm64
ldflags:
- -s -w
- -X github.com/user/devpack/pkg/version.Version={{.Version}}
- -X github.com/user/devpack/pkg/version.Commit={{.Commit}}
- -X github.com/user/devpack/pkg/version.Date={{.Date}}
archives:
- format: tar.gz
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
- '^chore:'
```