Files
DevPack/docs/ARCHITECTURE.md
2026-03-03 18:20:18 +08:00

752 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DevPack 架构设计文档
> 版本v1.0.0-draft
> 更新日期2026-03-03
> 作者DevPack Team
---
## 1. 架构概览
### 1.1 设计原则
| 原则 | 说明 |
|------|------|
| **单一二进制** | 编译为无依赖的单一可执行文件 |
| **插件化** | 采集器通过接口抽象,支持扩展 |
| **安全优先** | 敏感数据加密,操作可回滚 |
| **平台适配** | 通过平台适配层处理 OS 差异 |
| **幂等性** | 同一 Pack 多次还原结果一致 |
| **最小侵入** | 只修改用户级配置,不修改系统级设置(除非明确授权) |
### 1.2 高层架构图
```
┌──────────────────────────────────────────────────────────────────┐
│ CLI Layer (Cobra) │
│ ┌──────┐ ┌───────┐ ┌─────────┐ ┌────────┐ ┌──────┐ ┌────────┐ │
│ │ init │ │ scan │ │ capture │ │restore │ │ diff │ │export/ │ │
│ │ │ │ │ │ │ │ │ │ │ │import │ │
│ └──┬───┘ └───┬───┘ └────┬────┘ └───┬────┘ └──┬───┘ └───┬────┘ │
└─────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────┘
│ │ │ │ │ │
┌─────┴─────────┴──────────┴──────────┴─────────┴─────────┴──────┐
│ Core Engine Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ Collector │ │ Pack Engine │ │ Restore Engine │ │
│ │ Registry │ │ │ │ │ │
│ └──────┬───────┘ └──────┬───────┘ └────────────┬─────────────┘ │
│ │ │ │ │
│ ┌──────┴───────┐ ┌──────┴───────┐ ┌────────────┴─────────────┐ │
│ │ Profile │ │ Crypto │ │ Dependency Resolver │ │
│ │ Manager │ │ Module │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────────────┘ │
└─────────────────────────┬───────────────────────────────────────┘
┌─────────────────────────┴───────────────────────────────────────┐
│ Platform Abstraction Layer │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Windows │ │ macOS │ │ Linux │ │
│ │ Adapter │ │ Adapter │ │ Adapter │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────┴───────────────────────────────────────┐
│ Collector Plugins │
│ ┌─────────┐ ┌─────────┐ ┌────────┐ ┌───────┐ ┌─────┐ ┌─────┐ │
│ │ Runtime │ │ Package │ │ Editor │ │ Shell │ │ Git │ │ Env │ │
│ └─────────┘ └─────────┘ └────────┘ └───────┘ └─────┘ └─────┘ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Font │ │ SSH/GPG │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. 核心模块设计
### 2.1 采集器系统 (Collector System)
采集器是 DevPack 的核心,负责扫描和收集环境信息。所有采集器实现统一的接口。
#### 2.1.1 Collector 接口
```go
// Collector 定义了所有采集器必须实现的接口
type Collector interface {
// Name 返回采集器名称(唯一标识)
Name() string
// DisplayName 返回采集器的显示名称
DisplayName() string
// Description 返回采集器的描述信息
Description() string
// Category 返回采集器所属分类
Category() Category
// IsAvailable 检测当前系统是否支持此采集器
IsAvailable(ctx context.Context) bool
// Scan 扫描当前环境,返回扫描结果
Scan(ctx context.Context, opts ScanOptions) (*ScanResult, error)
// Capture 捕获环境数据,写入到指定目录
Capture(ctx context.Context, targetDir string, opts CaptureOptions) error
// Restore 从指定目录还原环境
Restore(ctx context.Context, sourceDir string, opts RestoreOptions) error
// Verify 验证还原后的环境是否正确
Verify(ctx context.Context) (*VerifyResult, error)
}
// Category 采集器分类
type Category string
const (
CategoryRuntime Category = "runtime" // 编程语言运行时
CategoryPackage Category = "package" // 包管理器
CategoryEditor Category = "editor" // 编辑器/IDE
CategoryShell Category = "shell" // Shell 配置
CategoryGit Category = "git" // Git 配置
CategoryEnv Category = "env" // 环境变量
CategoryFont Category = "font" // 字体
CategorySSH Category = "ssh" // SSH/GPG 密钥
CategoryCustom Category = "custom" // 自定义
)
// ScanResult 扫描结果
type ScanResult struct {
Collector string `json:"collector"`
Category Category `json:"category"`
Items []ScanItem `json:"items"`
Timestamp time.Time `json:"timestamp"`
Platform PlatformInfo `json:"platform"`
}
// ScanItem 单个扫描项
type ScanItem struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
Path string `json:"path,omitempty"`
Properties map[string]string `json:"properties,omitempty"`
Size int64 `json:"size,omitempty"`
Children []ScanItem `json:"children,omitempty"`
}
```
#### 2.1.2 采集器注册中心
```go
// Registry 采集器注册中心
type Registry struct {
collectors map[string]Collector
mu sync.RWMutex
}
// Register 注册一个采集器
func (r *Registry) Register(c Collector) error
// Get 获取指定名称的采集器
func (r *Registry) Get(name string) (Collector, bool)
// List 列出所有已注册的采集器
func (r *Registry) List() []Collector
// ListByCategory 按分类列出采集器
func (r *Registry) ListByCategory(cat Category) []Collector
// ScanAll 使用所有可用的采集器扫描
func (r *Registry) ScanAll(ctx context.Context, opts ScanOptions) ([]*ScanResult, error)
```
#### 2.1.3 内置采集器实现示例
以 Go 运行时采集器为例:
```go
type GoCollector struct{}
func (c *GoCollector) Name() string { return "go" }
func (c *GoCollector) DisplayName() string { return "Go Runtime" }
func (c *GoCollector) Category() Category { return CategoryRuntime }
func (c *GoCollector) Scan(ctx context.Context, opts ScanOptions) (*ScanResult, error) {
result := &ScanResult{
Collector: c.Name(),
Category: c.Category(),
}
// 检测 Go 版本
version, err := exec.CommandContext(ctx, "go", "version").Output()
// ... 解析版本信息
// 获取 go env 信息
envJSON, err := exec.CommandContext(ctx, "go", "env", "-json").Output()
// ... 解析环境变量
// 获取全局安装的工具
// ... 扫描 GOPATH/bin
return result, nil
}
```
### 2.2 打包引擎 (Pack Engine)
#### 2.2.1 Pack 文件格式
`.devpack` 文件本质上是一个经过组织的 tar.gz 归档文件:
```
my-env.devpack (tar.gz)
├── manifest.json # Pack 清单(元数据)
├── checksum.sha256 # 文件校验和
├── collectors/ # 各采集器数据
│ ├── runtime/
│ │ ├── go/
│ │ │ ├── metadata.json # Go 环境元数据
│ │ │ └── data/ # Go 相关数据文件
│ │ ├── node/
│ │ │ ├── metadata.json
│ │ │ └── data/
│ │ └── python/
│ │ ├── metadata.json
│ │ └── data/
│ ├── editor/
│ │ └── vscode/
│ │ ├── metadata.json
│ │ ├── extensions.json # 扩展列表
│ │ └── data/ # 设置文件
│ │ ├── settings.json
│ │ ├── keybindings.json
│ │ └── snippets/
│ ├── shell/
│ │ ├── powershell/
│ │ │ ├── metadata.json
│ │ │ └── data/
│ │ └── bash/
│ │ ├── metadata.json
│ │ └── data/
│ ├── package/
│ │ └── scoop/
│ │ ├── metadata.json
│ │ └── data/
│ ├── git/
│ │ ├── metadata.json
│ │ └── data/
│ └── env/
│ ├── metadata.json
│ └── data/
└── encrypted/ # 加密数据(可选)
└── ssh/
└── data.enc # 加密的 SSH 密钥
```
#### 2.2.2 Manifest 结构
```go
// Manifest Pack 清单
type Manifest struct {
// 元信息
Version string `json:"version"` // DevPack 版本
FormatVer string `json:"format_ver"` // Pack 格式版本
Name string `json:"name"` // Pack 名称
Description string `json:"description"` // 描述
Author string `json:"author"` // 作者
CreatedAt time.Time `json:"created_at"` // 创建时间
PackID string `json:"pack_id"` // 唯一 ID (UUID)
// 源环境信息
Source SourceInfo `json:"source"`
// 采集器数据索引
Collectors []CollectorEntry `json:"collectors"`
// 加密信息
Encryption *EncryptionInfo `json:"encryption,omitempty"`
// 校验信息
Checksum string `json:"checksum"` // 整包校验和
}
// SourceInfo 源环境信息
type SourceInfo struct {
Hostname string `json:"hostname"`
OS string `json:"os"` // windows, darwin, linux
OSVersion string `json:"os_version"`
Arch string `json:"arch"` // amd64, arm64
Username string `json:"username"`
}
// CollectorEntry 采集器条目
type CollectorEntry struct {
Name string `json:"name"`
Category Category `json:"category"`
ItemCount int `json:"item_count"`
DataPath string `json:"data_path"`
DataSize int64 `json:"data_size"`
Checksum string `json:"checksum"`
}
```
#### 2.2.3 打包流程
```
用户执行 capture 命令
┌─────────────────┐
│ 加载 Profile │ ─── 确定需要运行哪些采集器
└────────┬────────┘
┌─────────────────┐
│ 运行采集器 │ ─── 并行扫描 → 收集数据 → 写入临时目录
└────────┬────────┘
┌─────────────────┐
│ 生成 Manifest │ ─── 创建清单文件、计算校验和
└────────┬────────┘
┌─────────────────┐
│ 加密敏感数据 │ ─── 对标记为敏感的数据进行加密(可选)
└────────┬────────┘
┌─────────────────┐
│ 压缩归档 │ ─── tar.gz 打包
└────────┬────────┘
┌─────────────────┐
│ 输出 .devpack │ ─── 写入最终文件
└─────────────────┘
```
### 2.3 还原引擎 (Restore Engine)
#### 2.3.1 还原流程
```
用户执行 restore 命令
┌─────────────────┐
│ 校验 Pack 文件 │ ─── 检查完整性、版本兼容性
└────────┬────────┘
┌─────────────────┐
│ 解析 Manifest │ ─── 读取清单,确定还原内容
└────────┬────────┘
┌─────────────────┐
│ 平台兼容检查 │ ─── 确认目标平台与源平台匹配
└────────┬────────┘
┌─────────────────┐
│ 冲突检测 │ ─── 检测与现有环境的冲突
└────────┬────────┘
┌─────────────────────┐
│ 创建还原点(可选) │ ─── 备份当前环境用于回滚
└────────┬────────────┘
┌─────────────────┐
│ 依赖排序 │ ─── 按依赖关系排序安装顺序
└────────┬────────┘
┌─────────────────┐ ┌──────────────┐
│ 执行还原 │ ──▶ │ 逐项安装/配置 │
└────────┬────────┘ └──────────────┘
┌─────────────────┐
│ 验证还原结果 │ ─── 运行各采集器的验证逻辑
└────────┬────────┘
┌─────────────────┐
│ 生成还原报告 │ ─── 成功/失败/跳过的项目清单
└─────────────────┘
```
#### 2.3.2 冲突处理策略
```go
// ConflictStrategy 冲突处理策略
type ConflictStrategy int
const (
ConflictSkip ConflictStrategy = iota // 跳过(保留现有)
ConflictOverwrite // 覆盖(使用 Pack 中的)
ConflictMerge // 合并
ConflictPrompt // 询问用户
ConflictNewest // 使用较新版本
)
// ConflictItem 冲突项
type ConflictItem struct {
Collector string
ItemName string
CurrentVer string
PackVer string
Type ConflictType // VersionMismatch, AlreadyExists, DependencyConflict
}
```
### 2.4 配置文件管理 (Profile Manager)
#### 2.4.1 Profile 格式
使用 YAML 格式定义 Profile
```yaml
# ~/.devpack/profiles/golang-dev.yaml
name: golang-dev
description: "Go 全栈开发环境"
version: "1.0"
# 采集器配置
collectors:
runtime:
enabled: true
include:
- go
- node
exclude: []
options:
go:
capture_gopath_bin: true # 捕获 GOPATH/bin 下的工具
capture_go_env: true # 捕获 go env 配置
editor:
enabled: true
include:
- vscode
options:
vscode:
capture_extensions: true
capture_settings: true
capture_keybindings: true
capture_snippets: true
# 排除的扩展
exclude_extensions:
- "ms-vsliveshare.vsliveshare"
shell:
enabled: true
include:
- powershell
- bash
package:
enabled: true
include:
- scoop
git:
enabled: true
options:
capture_aliases: true
capture_hooks: false
env:
enabled: true
options:
# 只捕获匹配的环境变量
include_patterns:
- "GOPATH"
- "GOROOT"
- "PATH"
- "NODE_*"
exclude_patterns:
- "*_KEY"
- "*_SECRET"
- "*_TOKEN"
ssh:
enabled: false
# 还原选项
restore:
conflict_strategy: prompt # skip, overwrite, merge, prompt, newest
create_restore_point: true
dry_run_first: false
```
### 2.5 平台适配层 (Platform Abstraction Layer)
```go
// Platform 平台适配接口
type Platform interface {
// OS 返回操作系统标识
OS() string
// Arch 返回架构标识
Arch() string
// HomeDir 返回用户主目录
HomeDir() string
// ConfigDir 返回配置文件目录
ConfigDir() string
// DataDir 返回数据目录
DataDir() string
// GetEnvVar 获取环境变量
GetEnvVar(key string) string
// SetEnvVar 设置用户级环境变量
SetEnvVar(key, value string) error
// AddToPath 添加目录到 PATH
AddToPath(dir string) error
// IsAdmin 是否以管理员身份运行
IsAdmin() bool
// PackageManagers 返回可用的包管理器
PackageManagers() []string
// DefaultShell 返回默认 Shell
DefaultShell() string
// InstallFont 安装字体文件
InstallFont(fontPath string) error
// RunAsAdmin 以管理员权限运行命令
RunAsAdmin(cmd string, args ...string) error
}
```
各平台实现:
```go
// Windows 平台实现
type WindowsPlatform struct{}
func (p *WindowsPlatform) OS() string { return "windows" }
func (p *WindowsPlatform) HomeDir() string { return os.Getenv("USERPROFILE") }
func (p *WindowsPlatform) ConfigDir() string { return os.Getenv("APPDATA") }
func (p *WindowsPlatform) DefaultShell() string { return "powershell" }
func (p *WindowsPlatform) PackageManagers() []string {
var pms []string
if _, err := exec.LookPath("scoop"); err == nil { pms = append(pms, "scoop") }
if _, err := exec.LookPath("choco"); err == nil { pms = append(pms, "chocolatey") }
if _, err := exec.LookPath("winget"); err == nil { pms = append(pms, "winget") }
return pms
}
// macOS 平台实现
type DarwinPlatform struct{}
// Linux 平台实现
type LinuxPlatform struct{}
```
### 2.6 加密模块 (Crypto Module)
```go
// Encryptor 加密器接口
type Encryptor interface {
// Encrypt 使用密码加密数据
Encrypt(data []byte, password string) ([]byte, error)
// Decrypt 使用密码解密数据
Decrypt(encrypted []byte, password string) ([]byte, error)
}
// AESGCMEncryptor AES-256-GCM 加密实现
type AESGCMEncryptor struct{}
// 密钥派生使用 Argon2id
func deriveKey(password string, salt []byte) []byte {
return argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
}
```
---
## 3. 数据流
### 3.1 扫描 → 打包数据流
```
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐
│ 用户系统 │ ──▶ │ Collectors │ ──▶ │ ScanResult │ ──▶ │ 临时目录 │
│ (实际环境) │ │ (扫描采集) │ │ (结构化数据)│ │ (文件数据)│
└────────────┘ └────────────┘ └────────────┘ └────┬─────┘
┌────────────┐ ┌────────────┐ │
│ .devpack │ ◀── │ Pack 引擎 │ ◀────────┘
│ (归档文件) │ │ (压缩打包) │
└────────────┘ └────────────┘
```
### 3.2 导入 → 还原数据流
```
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐
│ .devpack │ ──▶ │ 解压校验 │ ──▶ │ Manifest │ ──▶ │ 还原计划 │
│ (归档文件) │ │ │ │ 解析 │ │ 生成 │
└────────────┘ └────────────┘ └────────────┘ └────┬─────┘
┌────────────┐ ┌────────────┐ │
│ 目标系统 │ ◀── │ Restore │ ◀────────┘
│ (已还原) │ │ Engine │
└────────────┘ └────────────┘
```
---
## 4. 技术选型
### 4.1 核心依赖
| 依赖 | 用途 | 选型理由 |
|------|------|---------|
| [cobra](https://github.com/spf13/cobra) | CLI 框架 | Go 生态最流行的 CLI 框架 |
| [viper](https://github.com/spf13/viper) | 配置管理 | 支持多种配置格式 |
| [zerolog](https://github.com/rs/zerolog) | 日志 | 高性能结构化日志 |
| [color](https://github.com/fatih/color) | 终端着色 | 美化 CLI 输出 |
| [progressbar](https://github.com/schollz/progressbar) | 进度条 | 长时操作反馈 |
| [survey](https://github.com/AlecAivazis/survey) | 交互式提示 | 用户交互 |
| [archiver](https://github.com/mholt/archiver) | 压缩归档 | 支持多种归档格式 |
| [go-yaml](https://github.com/go-yaml/yaml) | YAML 解析 | Profile 文件解析 |
| [uuid](https://github.com/google/uuid) | UUID 生成 | Pack ID 生成 |
| [golang.org/x/crypto](https://golang.org/x/crypto) | 加密库 | Argon2, AES |
### 4.2 构建工具
| 工具 | 用途 |
|------|------|
| Go 1.22+ | 编程语言 |
| Make / Task | 构建脚本 |
| GoReleaser | 多平台发布 |
| golangci-lint | 代码检查 |
| GitHub Actions | CI/CD |
---
## 5. 错误处理策略
### 5.1 错误分级
```go
// ErrorLevel 错误级别
type ErrorLevel int
const (
ErrorFatal ErrorLevel = iota // 致命错误,必须终止
ErrorCritical // 严重错误,当前采集器失败
ErrorWarning // 警告,可继续但需告知用户
ErrorInfo // 信息,记录但不影响流程
)
// CollectorError 采集器错误
type CollectorError struct {
Collector string
Level ErrorLevel
Message string
Cause error
Hint string // 给用户的建议
}
```
### 5.2 错误处理原则
1. **采集阶段** — 单个采集器失败不影响其他采集器
2. **打包阶段** — 失败的采集器数据不包含在 Pack 中,但 Pack 仍然生成
3. **还原阶段** — 根据策略决定是继续还是终止
4. **所有操作** — 详细日志记录,用户友好的错误信息
---
## 6. 安全设计
### 6.1 敏感数据识别
| 数据类型 | 敏感级别 | 处理方式 |
|---------|---------|---------|
| SSH 私钥 | 高 | AES-256 加密 |
| GPG 私钥 | 高 | AES-256 加密 |
| API Token | 高 | AES-256 加密或排除 |
| 环境变量中的密码 | 高 | 默认排除 |
| Git 凭证 | 高 | 默认排除 |
| IDE 设置 | 低 | 明文存储 |
| Shell 配置 | 中 | 扫描并警告内嵌 Token |
### 6.2 加密流程
```
用户密码 ──▶ Argon2id ──▶ 派生密钥 (256-bit)
敏感数据 ──▶ AES-256-GCM 加密 ──▶ 加密数据 + Nonce + Salt
存入 encrypted/ 目录
```
---
## 7. 可扩展性设计
### 7.1 插件系统(远期规划)
未来计划支持外部插件:
```go
// Plugin 外部插件接口
type Plugin interface {
Collector
// PluginInfo 返回插件元信息
PluginInfo() PluginMeta
}
type PluginMeta struct {
Name string `json:"name"`
Version string `json:"version"`
Author string `json:"author"`
MinDevPack string `json:"min_devpack_version"`
}
```
插件发现机制:
1. `~/.devpack/plugins/` 目录下的可执行文件
2. 通过 Go Plugin 机制加载 `.so` / `.dll`
3. 通过 gRPC/JSON-RPC 与外部进程通信(推荐,跨语言)
---
## 8. 测试策略
### 8.1 测试层级
| 层级 | 范围 | 工具 |
|------|------|------|
| 单元测试 | 各模块独立逻辑 | Go testing + testify |
| 集成测试 | 模块间协作 | Go testing |
| 端到端测试 | 完整的 capture → restore 流程 | 脚本 + Docker/VM |
| 平台测试 | 各操作系统适配 | GitHub Actions Matrix |
### 8.2 测试环境
- CI 环境使用 GitHub Actions 矩阵构建Windows/macOS/Linux
- 端到端测试使用虚拟机或容器模拟真实环境
- Mock 框架用于隔离外部依赖(如包管理器)