# 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/): ``` (): [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 ` 校验 | | 还原权限不足 | 以管理员身份运行 | | 跨版本不兼容 | 检查 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:' ```