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

27 KiB
Raw Blame History

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 错误处理原则

  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 插件系统(远期规划)

未来计划支持外部插件:

// 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 框架用于隔离外部依赖(如包管理器)