18 KiB
18 KiB
DevPack 开发指南
版本:v1.0.0-draft
更新日期:2026-03-03
作者:DevPack Team
1. 开发环境搭建
1.1 前置要求
| 工具 | 最低版本 | 安装方式 |
|---|---|---|
| Go | 1.22+ | golang.org |
| Git | 2.30+ | 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 获取代码
git clone https://github.com/user/devpack.git
cd devpack
1.3 安装依赖
go mod download
1.4 验证环境
# 运行测试
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 和 Go Code Review Comments。
命名规范
// ✅ 包名:小写单词,不用下划线
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")
错误处理
// ✅ 使用 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 使用
// ✅ 第一个参数传递 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 提交规范
<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 开发流程
- 创建分支:
git checkout -b feature/xxx develop - 开发 & 测试: 编写代码 + 单元测试
- 代码检查:
make lint - 提交: 遵循 Conventional Commits
- 推送 & PR: 推送分支,创建 Pull Request
- Code Review: 至少一人 Review 通过
- 合并: Squash Merge 到 develop
4.3 常用 Make 命令
# 构建
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: 创建采集器文件
// 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: 注册采集器
// 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: 编写测试
// 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 日志级别
# 设置日志级别
DEVPACK_LOG_LEVEL=debug devpack scan
# 或通过命令行参数
devpack scan --log-level debug
| 级别 | 用途 |
|---|---|
trace |
非常详细的调试信息 |
debug |
调试信息 |
info |
正常操作信息(默认) |
warn |
警告 |
error |
错误 |
fatal |
致命错误 |
6.2 VS Code 调试配置
// .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 版本号规范
MAJOR.MINOR.PATCH[-PRERELEASE]
- MAJOR: 不兼容的 API 变更
- MINOR: 向下兼容的功能新增
- PATCH: 向下兼容的 Bug 修复
7.2 发布步骤
# 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 配置
# .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:'