27 KiB
27 KiB
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 接口
// 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 采集器注册中心
// 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 运行时采集器为例:
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 结构
// 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 冲突处理策略
// 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:
# ~/.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)
// 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
}
各平台实现:
// 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)
// 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 | CLI 框架 | Go 生态最流行的 CLI 框架 |
| viper | 配置管理 | 支持多种配置格式 |
| zerolog | 日志 | 高性能结构化日志 |
| color | 终端着色 | 美化 CLI 输出 |
| progressbar | 进度条 | 长时操作反馈 |
| survey | 交互式提示 | 用户交互 |
| archiver | 压缩归档 | 支持多种归档格式 |
| go-yaml | YAML 解析 | Profile 文件解析 |
| uuid | UUID 生成 | Pack ID 生成 |
| golang.org/x/crypto | 加密库 | Argon2, AES |
4.2 构建工具
| 工具 | 用途 |
|---|---|
| Go 1.22+ | 编程语言 |
| Make / Task | 构建脚本 |
| GoReleaser | 多平台发布 |
| golangci-lint | 代码检查 |
| GitHub Actions | CI/CD |
5. 错误处理策略
5.1 错误分级
// 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 错误处理原则
- 采集阶段 — 单个采集器失败不影响其他采集器
- 打包阶段 — 失败的采集器数据不包含在 Pack 中,但 Pack 仍然生成
- 还原阶段 — 根据策略决定是继续还是终止
- 所有操作 — 详细日志记录,用户友好的错误信息
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 插件系统(远期规划)
未来计划支持外部插件:
// 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"`
}
插件发现机制:
~/.devpack/plugins/目录下的可执行文件- 通过 Go Plugin 机制加载
.so/.dll - 通过 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 框架用于隔离外部依赖(如包管理器)