installerbuilder/doc/design.md

30 KiB
Raw Permalink Blame History

详细设计文档

本文档详细描述了Installer Builder项目的设计包括各组件详细设计、类/接口定义、工作流程和错误处理策略等内容。这个文档将作为开发实现的具体指导。

1. 组件详细设计

1.1 配置管理器

配置管理器负责解析、验证和管理构建配置。

1.1.1 配置模型

// Config 表示安装包构建的完整配置
type Config struct {
    // 基本信息
    Name        string   `yaml:"name" json:"name"`             // 应用名称
    Version     string   `yaml:"version" json:"version"`       // 应用版本
    Description string   `yaml:"description" json:"description"` // 应用描述
    Author      string   `yaml:"author" json:"author"`         // 作者信息
    License     string   `yaml:"license" json:"license"`       // 许可证信息
    
    // 构建目标
    Targets     []Target `yaml:"targets" json:"targets"`       // 构建目标列表
    
    // 文件和目录
    Files       []File   `yaml:"files" json:"files"`           // 要包含的文件
    Directories []Directory `yaml:"directories" json:"directories"` // 要包含的目录
    
    // 脚本
    PreInstall  Script   `yaml:"preInstall" json:"preInstall"`   // 安装前脚本
    PostInstall Script   `yaml:"postInstall" json:"postInstall"` // 安装后脚本
    
    // 依赖
    Dependencies []Dependency `yaml:"dependencies" json:"dependencies"` // 依赖项
    
    // 插件配置
    Plugins     map[string]interface{} `yaml:"plugins" json:"plugins"` // 插件特定配置
}

// Target 表示构建目标
type Target struct {
    Platform    string   `yaml:"platform" json:"platform"`     // 目标平台 (windows, linux)
    Arch        string   `yaml:"arch" json:"arch"`             // 目标架构 (amd64, arm64)
    PackageType string   `yaml:"packageType" json:"packageType"` // 包类型 (msi, deb, rpm, zip)
    OutputPath  string   `yaml:"outputPath" json:"outputPath"` // 输出路径
}

// File 表示要包含在安装包中的文件
type File struct {
    Source      string   `yaml:"source" json:"source"`         // 源文件路径
    Destination string   `yaml:"destination" json:"destination"` // 目标路径
    Permissions string   `yaml:"permissions" json:"permissions"` // 文件权限
}

// Directory 表示要包含在安装包中的目录
type Directory struct {
    Source      string   `yaml:"source" json:"source"`         // 源目录路径
    Destination string   `yaml:"destination" json:"destination"` // 目标路径
    Permissions string   `yaml:"permissions" json:"permissions"` // 目录权限
    Recursive   bool     `yaml:"recursive" json:"recursive"`   // 是否递归包含子目录
}

// Script 表示安装脚本
type Script struct {
    Path        string   `yaml:"path" json:"path"`             // 脚本文件路径
    Type        string   `yaml:"type" json:"type"`             // 脚本类型 (node, shell)
    Args        []string `yaml:"args" json:"args"`             // 脚本参数
}

// Dependency 表示依赖项
type Dependency struct {
    Name        string   `yaml:"name" json:"name"`             // 依赖名称
    Version     string   `yaml:"version" json:"version"`       // 依赖版本
    Type        string   `yaml:"type" json:"type"`             // 依赖类型
}

1.1.2 配置解析器

// ConfigParser 负责解析配置文件
type ConfigParser interface {
    // Parse 从指定路径解析配置文件
    Parse(path string) (*Config, error)
    
    // Validate 验证配置是否有效
    Validate(config *Config) error
}

// YAMLConfigParser 实现了YAML格式的配置解析
type YAMLConfigParser struct {
    schema *jsonschema.Schema // JSON Schema用于验证
}

// JSONConfigParser 实现了JSON格式的配置解析
type JSONConfigParser struct {
    schema *jsonschema.Schema // JSON Schema用于验证
}

1.1.3 配置验证器

// ConfigValidator 负责验证配置
type ConfigValidator interface {
    // Validate 验证配置是否有效
    Validate(config *Config) error
}

// SchemaValidator 使用JSON Schema验证配置
type SchemaValidator struct {
    schema *jsonschema.Schema
}

1.2 构建协调器

构建协调器负责协调整个构建过程,包括调用平台适配器、包构建器和脚本执行器。

// BuildCoordinator 负责协调构建过程
type BuildCoordinator interface {
    // Build 执行构建过程
    Build(config *Config) ([]BuildResult, error)
    
    // BuildTarget 构建特定目标
    BuildTarget(config *Config, target Target) (*BuildResult, error)
}

// DefaultBuildCoordinator 是BuildCoordinator的默认实现
type DefaultBuildCoordinator struct {
    platformAdapters map[string]PlatformAdapter
    packageBuilders  map[string]PackageBuilder
    scriptExecutor   ScriptExecutor
    pluginManager    PluginManager
    logger           Logger
}

// BuildResult 表示构建结果
type BuildResult struct {
    Target      Target  // 构建目标
    OutputPath  string  // 输出文件路径
    Success     bool    // 是否成功
    Error       error   // 错误信息
    BuildTime   time.Duration // 构建时间
}

1.3 平台适配层

平台适配层处理不同操作系统和架构的特定逻辑。

// PlatformAdapter 处理平台特定的逻辑
type PlatformAdapter interface {
    // GetPlatformInfo 获取平台信息
    GetPlatformInfo() PlatformInfo
    
    // PrepareEnvironment 准备构建环境
    PrepareEnvironment(config *Config, target Target) error
    
    // CleanupEnvironment 清理构建环境
    CleanupEnvironment(config *Config, target Target) error
}

// PlatformInfo 包含平台特定信息
type PlatformInfo struct {
    Name            string // 平台名称
    Version         string // 平台版本
    Arch            string // 平台架构
    DefaultInstallDir string // 默认安装目录
    PathSeparator   string // 路径分隔符
}

// WindowsAdapter 实现Windows平台的适配
type WindowsAdapter struct {
    // Windows特定字段
}

// LinuxAdapter 实现Linux平台的适配
type LinuxAdapter struct {
    // Linux特定字段
}

1.4 包构建器

包构建器负责生成不同类型的安装包。

// PackageBuilder 负责构建特定类型的安装包
type PackageBuilder interface {
    // Build 构建安装包
    Build(config *Config, target Target) (*BuildResult, error)
    
    // GetSupportedPlatforms 获取支持的平台
    GetSupportedPlatforms() []string
}

// MSIBuilder 构建Windows MSI安装包
type MSIBuilder struct {
    tempDir     string
    platformAdapter PlatformAdapter
    logger      Logger
}

// DEBBuilder 构建Linux DEB安装包
type DEBBuilder struct {
    tempDir     string
    platformAdapter PlatformAdapter
    logger      Logger
}

// RPMBuilder 构建Linux RPM安装包
type RPMBuilder struct {
    tempDir     string
    platformAdapter PlatformAdapter
    logger      Logger
}

// ZipBuilder 构建跨平台ZIP压缩包
type ZipBuilder struct {
    tempDir     string
    platformAdapter PlatformAdapter
    logger      Logger
}

1.5 脚本执行器

脚本执行器负责执行安装前后脚本。

// ScriptExecutor 负责执行脚本
type ScriptExecutor interface {
    // Execute 执行脚本
    Execute(script Script, env map[string]string) (*ScriptResult, error)
}

// NodeScriptExecutor 执行Node.js脚本
type NodeScriptExecutor struct {
    nodePath    string
    logger      Logger
}

// ShellScriptExecutor 执行Shell脚本
type ShellScriptExecutor struct {
    shellPath   string
    logger      Logger
}

// ScriptResult 表示脚本执行结果
type ScriptResult struct {
    ExitCode    int       // 退出码
    Output      string    // 标准输出
    Error       string    // 标准错误
    ExecutionTime time.Duration // 执行时间
}

1.6 插件系统

插件系统提供扩展系统功能的机制。

// Plugin 表示插件接口
type Plugin interface {
    // Init 初始化插件
    Init(config map[string]interface{}) error
    
    // GetName 获取插件名称
    GetName() string
    
    // GetVersion 获取插件版本
    GetVersion() string
}

// PackageTypePlugin 扩展包类型支持
type PackageTypePlugin interface {
    Plugin
    PackageBuilder
}

// PlatformPlugin 扩展平台支持
type PlatformPlugin interface {
    Plugin
    PlatformAdapter
}

// PluginManager 负责管理插件
type PluginManager interface {
    // LoadPlugin 加载插件
    LoadPlugin(path string) (Plugin, error)
    
    // GetPlugin 获取插件
    GetPlugin(name string) (Plugin, error)
    
    // GetAllPlugins 获取所有插件
    GetAllPlugins() []Plugin
}

2. 核心接口定义

2.1 日志接口

// Logger 提供日志功能
type Logger interface {
    Debug(msg string, args ...interface{})
    Info(msg string, args ...interface{})
    Warn(msg string, args ...interface{})
    Error(msg string, args ...interface{})
    Fatal(msg string, args ...interface{})
}

// DefaultLogger 是Logger的默认实现
type DefaultLogger struct {
    level LogLevel
}

// LogLevel 表示日志级别
type LogLevel int

const (
    DebugLevel LogLevel = iota
    InfoLevel
    WarnLevel
    ErrorLevel
    FatalLevel
)

2.2 错误接口

// Error 表示构建过程中的错误
type Error interface {
    error
    // Code 返回错误代码
    Code() string
    // Component 返回发生错误的组件
    Component() string
    // Details 返回详细错误信息
    Details() map[string]interface{}
}

// BuildError 实现了Error接口
type BuildError struct {
    code      string
    component string
    message   string
    details   map[string]interface{}
    cause     error
}

2.3 资源管理接口

// ResourceManager 管理构建过程中的资源
type ResourceManager interface {
    // CreateTempDir 创建临时目录
    CreateTempDir(prefix string) (string, error)
    
    // CleanupTempDir 清理临时目录
    CleanupTempDir(path string) error
    
    // CopyFile 复制文件
    CopyFile(src, dst string) error
    
    // CopyDir 复制目录
    CopyDir(src, dst string, recursive bool) error
}

// DefaultResourceManager 是ResourceManager的默认实现
type DefaultResourceManager struct {
    logger Logger
}

3. 工作流程

3.1 配置解析流程

flowchart TD
    A[读取配置文件] --> B[检测文件格式]
    B -->|YAML| C[YAML解析器]
    B -->|JSON| D[JSON解析器]
    C --> E[创建配置对象]
    D --> E
    E --> F[验证配置]
    F -->|验证失败| G[返回错误]
    F -->|验证成功| H[返回配置对象]

3.2 构建流程

flowchart TD
    A[接收构建请求] --> B[解析配置]
    B --> C[验证配置]
    C -->|验证失败| D[返回错误]
    C -->|验证成功| E[准备构建环境]
    E --> F[执行安装前脚本]
    F --> G[并行构建多个目标]
    G --> H[执行安装后脚本]
    H --> I[清理构建环境]
    I --> J[返回构建结果]

3.3 包构建流程

flowchart TD
    A[选择包构建器] --> B[创建临时目录]
    B --> C[复制文件和目录]
    C --> D[生成包特定文件]
    D --> E[调用包构建工具]
    E --> F[验证构建结果]
    F -->|构建失败| G[返回错误]
    F -->|构建成功| H[移动到输出目录]
    H --> I[清理临时文件]
    I --> J[返回构建结果]

3.4 脚本执行流程

flowchart TD
    A[接收脚本执行请求] --> B[检查脚本类型]
    B -->|Node.js| C[选择Node.js执行器]
    B -->|Shell| D[选择Shell执行器]
    C --> E[准备执行环境]
    D --> E
    E --> F[执行脚本]
    F --> G[捕获输出和错误]
    G --> H[检查退出码]
    H -->|非零| I[返回错误]
    H -->|零| J[返回成功结果]

4. 错误处理策略

4.1 错误类型

// 错误代码常量
const (
    // 配置错误
    ErrConfigParse       = "CONFIG_PARSE_ERROR"       // 配置解析错误
    ErrConfigValidation  = "CONFIG_VALIDATION_ERROR"  // 配置验证错误
    
    // 构建错误
    ErrBuildFailed       = "BUILD_FAILED"             // 构建失败
    ErrBuildEnvironment  = "BUILD_ENVIRONMENT_ERROR"  // 构建环境错误
    
    // 平台错误
    ErrPlatformNotSupported = "PLATFORM_NOT_SUPPORTED" // 平台不支持
    ErrArchNotSupported  = "ARCH_NOT_SUPPORTED"       // 架构不支持
    
    // 包构建错误
    ErrPackageTypeFailed = "PACKAGE_TYPE_FAILED"      // 包类型构建失败
    ErrPackageToolNotFound = "PACKAGE_TOOL_NOT_FOUND" // 包构建工具未找到
    
    // 脚本错误
    ErrScriptExecution   = "SCRIPT_EXECUTION_ERROR"   // 脚本执行错误
    ErrScriptNotFound    = "SCRIPT_NOT_FOUND"         // 脚本未找到
    
    // 插件错误
    ErrPluginLoad        = "PLUGIN_LOAD_ERROR"        // 插件加载错误
    ErrPluginInit        = "PLUGIN_INIT_ERROR"        // 插件初始化错误
    
    // 资源错误
    ErrResourceNotFound  = "RESOURCE_NOT_FOUND"       // 资源未找到
    ErrResourceCopy      = "RESOURCE_COPY_ERROR"      // 资源复制错误
)

4.2 错误处理原则

  1. 错误传播:错误应该向上传播,直到能够适当处理它们的层级
  2. 错误包装:使用fmt.Errorf%w包装错误,保留原始错误信息
  3. 错误上下文:添加足够的上下文信息,帮助诊断问题
  4. 错误恢复:在适当的情况下进行错误恢复,避免整个构建过程失败

4.3 错误处理示例

func (b *DefaultBuildCoordinator) BuildTarget(config *Config, target Target) (*BuildResult, error) {
    // 检查平台支持
    adapter, ok := b.platformAdapters[target.Platform]
    if !ok {
        return nil, &BuildError{
            code:      ErrPlatformNotSupported,
            component: "BuildCoordinator",
            message:   fmt.Sprintf("Platform %s is not supported", target.Platform),
            details:   map[string]interface{}{"target": target},
        }
    }
    
    // 准备环境
    if err := adapter.PrepareEnvironment(config, target); err != nil {
        return nil, fmt.Errorf("failed to prepare environment: %w", err)
    }
    
    // 构建包
    builder, ok := b.packageBuilders[target.PackageType]
    if !ok {
        return nil, &BuildError{
            code:      ErrPackageTypeFailed,
            component: "BuildCoordinator",
            message:   fmt.Sprintf("Package type %s is not supported", target.PackageType),
            details:   map[string]interface{}{"target": target},
        }
    }
    
    result, err := builder.Build(config, target)
    if err != nil {
        return nil, fmt.Errorf("failed to build package: %w", err)
    }
    
    // 清理环境
    if err := adapter.CleanupEnvironment(config, target); err != nil {
        b.logger.Warn("Failed to cleanup environment", "error", err)
        // 继续执行,不返回错误
    }
    
    return result, nil
}

5. 测试策略

5.1 测试级别

5.1.1 单元测试

  • 测试单个组件的功能
  • 使用模拟mock隔离依赖
  • 覆盖核心逻辑和边界条件
func TestYAMLConfigParser_Parse(t *testing.T) {
    tests := []struct {
        name     string
        input    string
        expected *Config
        wantErr  bool
    }{
        {
            name:  "Valid config",
            input: "testdata/valid_config.yaml",
            expected: &Config{
                Name:    "TestApp",
                Version: "1.0.0",
                // ...
            },
            wantErr: false,
        },
        {
            name:     "Invalid config",
            input:    "testdata/invalid_config.yaml",
            expected: nil,
            wantErr:  true,
        },
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            parser := NewYAMLConfigParser()
            got, err := parser.Parse(tt.input)
            
            if tt.wantErr {
                assert.Error(t, err)
            } else {
                assert.NoError(t, err)
                assert.Equal(t, tt.expected, got)
            }
        })
    }
}

5.1.2 集成测试

  • 测试多个组件的交互
  • 验证组件之间的接口契约
  • 使用真实依赖,但可能使用测试替身
func TestBuildCoordinator_Integration(t *testing.T) {
    // 设置测试环境
    tempDir, err := ioutil.TempDir("", "builder-test")
    require.NoError(t, err)
    defer os.RemoveAll(tempDir)
    
    // 创建真实的依赖组件
    logger := NewDefaultLogger(InfoLevel)
    resourceManager := NewDefaultResourceManager(logger)
    
    // 创建构建协调器
    coordinator := NewDefaultBuildCoordinator(
        map[string]PlatformAdapter{
            "windows": NewWindowsAdapter(logger),
            "linux":   NewLinuxAdapter(logger),
        },
        map[string]PackageBuilder{
            "zip": NewZipBuilder(tempDir, resourceManager, logger),
        },
        NewNodeScriptExecutor("node", logger),
        NewDefaultPluginManager(logger),
        logger,
    )
    
    // 准备测试配置
    config := &Config{
        Name:    "TestApp",
        Version: "1.0.0",
        Targets: []Target{
            {
                Platform:    "windows",
                Arch:        "amd64",
                PackageType: "zip",
                OutputPath:  filepath.Join(tempDir, "output"),
            },
        },
        // ...
    }
    
    // 执行构建
    results, err := coordinator.Build(config)
    require.NoError(t, err)
    
    // 验证结果
    require.Len(t, results, 1)
    assert.True(t, results[0].Success)
    assert.FileExists(t, results[0].OutputPath)
}

5.1.3 端到端测试

  • 测试完整的构建流程
  • 验证生成的安装包
  • 测试安装和卸载过程
func TestEndToEnd(t *testing.T) {
    if testing.Short() {
        t.Skip("Skipping end-to-end test in short mode")
    }
    
    // 设置测试环境
    tempDir, err := ioutil.TempDir("", "e2e-test")
    require.NoError(t, err)
    defer os.RemoveAll(tempDir)
    
    // 准备测试应用
    appDir := filepath.Join(tempDir, "app")
    require.NoError(t, os.MkdirAll(appDir, 0755))
    
    // 创建测试文件
    testFile := filepath.Join(appDir, "test.txt")
    require.NoError(t, ioutil.WriteFile(testFile, []byte("test content"), 0644))
    
    // 创建配置文件
    configPath := filepath.Join(tempDir, "config.yaml")
    configContent := `
name: TestApp
version: 1.0.0
targets:
  - platform: windows
    arch: amd64
    packageType: zip
    outputPath: output
files:
  - source: app/test.txt
    destination: test.txt
`
    require.NoError(t, ioutil.WriteFile(configPath, []byte(configContent), 0644))
    
    // 执行CLI命令
    cmd := exec.Command("installer-builder", "build", "--config", configPath)
    cmd.Dir = tempDir
    output, err := cmd.CombinedOutput()
    require.NoError(t, err, "CLI command failed: %s", output)
    
    // 验证输出文件
    outputFile := filepath.Join(tempDir, "output", "TestApp-1.0.0-windows-amd64.zip")
    assert.FileExists(t, outputFile)
    
    // 解压并验证内容
    extractDir := filepath.Join(tempDir, "extract")
    require.NoError(t, os.MkdirAll(extractDir, 0755))
    
    // 解压ZIP文件
    cmd = exec.Command("unzip", outputFile, "-d", extractDir)
    require.NoError(t, cmd.Run())
    
    // 验证文件内容
    extractedFile := filepath.Join(extractDir, "test.txt")
    assert.FileExists(t, extractedFile)
    
    content, err := ioutil.ReadFile(extractedFile)
    require.NoError(t, err)
    assert.Equal(t, "test content", string(content))
}

5.2 测试覆盖率目标

  • 核心组件80%以上的代码覆盖率
  • 工具类和辅助函数70%以上的代码覆盖率
  • 整体项目75%以上的代码覆盖率

5.3 测试工具

  • 使用Go标准库的testing
  • 使用testify库提供断言和模拟功能
  • 使用go-cmp进行深度比较
  • 使用go test -race检测竞态条件

6. 部署和发布策略

6.1 版本控制

  • 使用语义化版本Semantic Versioning
  • 主版本号不兼容的API变更
  • 次版本号:向后兼容的功能性新增
  • 修订号:向后兼容的问题修正

6.2 构建流程

flowchart TD
    A[代码提交] --> B[自动化测试]
    B -->|测试通过| C[构建二进制]
    C --> D[打包]
    D --> E[发布]
    B -->|测试失败| F[通知开发者]

6.3 发布渠道

  • GitHub Releases发布二进制文件和源代码
  • Docker Hub发布Docker镜像
  • HomebrewmacOS用户的包管理器
  • APT/YUM仓库Linux用户的包管理器

6.4 持续集成/持续部署

  • 使用GitHub Actions进行CI/CD
  • 每次提交运行测试
  • 每次发布标签构建和发布二进制文件

7. 性能优化策略

7.1 并行构建

  • 使用工作池并行构建多个目标
  • 限制并发数量,避免资源竞争
func (b *DefaultBuildCoordinator) Build(config *Config) ([]BuildResult, error) {
    results := make([]BuildResult, 0, len(config.Targets))
    var mu sync.Mutex
    var wg sync.WaitGroup
    
    // 创建工作池,限制并发数
    semaphore := make(chan struct{}, runtime.NumCPU())
    
    // 执行安装前脚本
    if config.PreInstall.Path != "" {
        result, err := b.scriptExecutor.Execute(config.PreInstall, nil)
        if err != nil {
            return nil, fmt.Errorf("pre-install script failed: %w", err)
        }
        if result.ExitCode != 0 {
            return nil, fmt.Errorf("pre-install script failed with exit code %d", result.ExitCode)
        }
    }
    
    // 并行构建多个目标
    errCh := make(chan error, len(config.Targets))
    
    for _, target := range config.Targets {
        wg.Add(1)
        go func(t Target) {
            defer wg.Done()
            
            // 获取信号量
            semaphore <- struct{}{}
            defer func() { <-semaphore }()
            
            result, err := b.BuildTarget(config, t)
            if err != nil {
                errCh <- err
                return
            }
            
            mu.Lock()
            results = append(results, *result)
            mu.Unlock()
        }(target)
    }
    
    // 等待所有构建完成
    wg.Wait()
    close(errCh)
    
    // 检查错误
    for err := range errCh {
        if err != nil {
            return results, err
        }
    }
    
    // 执行安装后脚本
    if config.PostInstall.Path != "" {
        result, err := b.scriptExecutor.Execute(config.PostInstall, nil)
        if err != nil {
            return results, fmt.Errorf("post-install script failed: %w", err)
        }
        if result.ExitCode != 0 {
            return results, fmt.Errorf("post-install script failed with exit code %d", result.ExitCode)
        }
    }
    
    return results, nil
}

7.2 资源管理

  • 重用临时目录减少I/O操作
  • 使用缓冲I/O提高文件操作效率
  • 及时清理临时资源,避免磁盘空间耗尽

7.3 缓存策略

  • 缓存构建依赖,避免重复下载
  • 缓存中间构建产物,加速增量构建
  • 使用分层缓存,提高缓存命中率

8. 安全策略

8.1 安全检查

  • 验证脚本和文件的完整性
  • 检查依赖项的安全漏洞
  • 限制脚本执行权限

8.2 安全最佳实践

  • 使用最小权限原则执行脚本
  • 避免在脚本中硬编码敏感信息
  • 对用户输入进行验证和清理
  • 使用安全的临时文件处理方式

8.3 数据安全

  • 加密敏感配置信息
  • 安全存储和传输凭证
  • 确保安装包内容的完整性

9. 升级策略

9.1 版本检测

// VersionChecker 负责检测版本信息
type VersionChecker interface {
    // CheckForUpgrade 检查是否有可用升级
    CheckForUpgrade(currentVersion string) (*UpgradeInfo, error)
    
    // CompareVersions 比较两个版本
    CompareVersions(v1, v2 string) (int, error)
}

// UpgradeInfo 包含升级信息
type UpgradeInfo struct {
    AvailableVersion string            // 可用的最新版本
    ReleaseNotes     string            // 发布说明
    DownloadURL      string            // 下载URL
    Metadata         map[string]string // 其他元数据
}

9.2 升级流程

flowchart TD
    A[检测当前版本] --> B[检查可用升级]
    B -->|无可用升级| C[结束流程]
    B -->|有可用升级| D[下载新版本]
    D --> E[验证完整性]
    E -->|验证失败| F[报告错误]
    E -->|验证成功| G[备份当前版本]
    G --> H[安装新版本]
    H -->|安装失败| I[回滚到备份]
    H -->|安装成功| J[清理备份]
    J --> K[完成升级]

9.3 数据迁移

  • 保留用户配置和数据
  • 提供配置迁移工具
  • 支持回滚到之前版本

9.4 升级模式

9.4.1 原地升级

原地升级会替换现有安装的文件,保留配置和数据。

// InPlaceUpgrader 执行原地升级
type InPlaceUpgrader struct {
    backupDir   string
    logger      Logger
}

func (u *InPlaceUpgrader) Upgrade(config *Config) error {
    // 备份当前安装
    // 安装新版本
    // 迁移配置
    // 清理备份(如果成功)
}

9.4.2 并行安装

并行安装会在不同位置安装新版本,然后切换到新版本。

// ParallelUpgrader 执行并行安装升级
type ParallelUpgrader struct {
    installDir  string
    logger      Logger
}

func (u *ParallelUpgrader) Upgrade(config *Config) error {
    // 在新位置安装
    // 迁移配置和数据
    // 切换活动版本
    // 清理旧版本(可选)
}

10. 国际化和本地化

10.1 消息本地化

// Localizer 负责消息本地化
type Localizer interface {
    // Localize 本地化消息
    Localize(key string, args map[string]interface{}) string
    
    // SetLocale 设置当前语言环境
    SetLocale(locale string) error
}

// DefaultLocalizer 是Localizer的默认实现
type DefaultLocalizer struct {
    locale      string
    messages    map[string]map[string]string
}

10.2 支持的语言

  • 英语(默认)
  • 简体中文
  • 日语
  • 德语
  • 西班牙语

10.3 本地化资源

  • 界面文本
  • 错误消息
  • 安装向导
  • 文档

11. 命令行接口

11.1 命令结构

installer-builder [global options] command [command options] [arguments...]

COMMANDS:
   build    构建安装包
   validate 验证配置文件
   init     初始化配置文件模板
   help     显示帮助信息

GLOBAL OPTIONS:
   --verbose, -v    启用详细日志输出
   --quiet, -q      只显示错误信息
   --config FILE    指定配置文件路径
   --help, -h       显示帮助信息
   --version        显示版本信息

11.2 构建命令

installer-builder build [options]

OPTIONS:
   --config FILE       指定配置文件路径
   --target PLATFORM   只构建指定平台的安装包
   --arch ARCH         只构建指定架构的安装包
   --output DIR        指定输出目录
   --clean             构建前清理输出目录
   --parallel NUM      并行构建的数量

11.3 验证命令

installer-builder validate [options]

OPTIONS:
   --config FILE    指定配置文件路径
   --strict         启用严格验证模式

12. 配置文件示例

12.1 YAML配置示例

name: "MyApp"
version: "1.0.0"
description: "My Awesome Application"
author: "John Doe"
license: "MIT"

targets:
  - platform: "windows"
    arch: "amd64"
    packageType: "msi"
    outputPath: "dist/windows"
  - platform: "linux"
    arch: "amd64"
    packageType: "deb"
    outputPath: "dist/linux"
  - platform: "linux"
    arch: "amd64"
    packageType: "rpm"
    outputPath: "dist/linux"

files:
  - source: "bin/myapp.exe"
    destination: "bin/myapp.exe"
    permissions: "0755"
  - source: "README.md"
    destination: "docs/README.md"
    permissions: "0644"

directories:
  - source: "assets"
    destination: "assets"
    permissions: "0755"
    recursive: true

preInstall:
  path: "scripts/pre-install.sh"
  type: "shell"
  args: ["--check-deps"]

postInstall:
  path: "scripts/post-install.js"
  type: "node"
  args: ["--configure"]

dependencies:
  - name: "nodejs"
    version: ">=14.0.0"
    type: "runtime"
  - name: "dotnet-runtime"
    version: ">=5.0.0"
    type: "runtime"

plugins:
  notarize:
    enabled: true
    identity: "Developer ID"
  compression:
    level: "high"

12.2 JSON配置示例

{
  "name": "MyApp",
  "version": "1.0.0",
  "description": "My Awesome Application",
  "author": "John Doe",
  "license": "MIT",
  "targets": [
    {
      "platform": "windows",
      "arch": "amd64",
      "packageType": "msi",
      "outputPath": "dist/windows"
    },
    {
      "platform": "linux",
      "arch": "amd64",
      "packageType": "deb",
      "outputPath": "dist/linux"
    },
    {
      "platform": "linux",
      "arch": "amd64",
      "packageType": "rpm",
      "outputPath": "dist/linux"
    }
  ],
  "files": [
    {
      "source": "bin/myapp.exe",
      "destination": "bin/myapp.exe",
      "permissions": "0755"
    },
    {
      "source": "README.md",
      "destination": "docs/README.md",
      "permissions": "0644"
    }
  ],
  "directories": [
    {
      "source": "assets",
      "destination": "assets",
      "permissions": "0755",
      "recursive": true
    }
  ],
  "preInstall": {
    "path": "scripts/pre-install.sh",
    "type": "shell",
    "args": ["--check-deps"]
  },
  "postInstall": {
    "path": "scripts/post-install.js",
    "type": "node",
    "args": ["--configure"]
  },
  "dependencies": [
    {
      "name": "nodejs",
      "version": ">=14.0.0",
      "type": "runtime"
    },
    {
      "name": "dotnet-runtime",
      "version": ">=5.0.0",
      "type": "runtime"
    }
  ],
  "plugins": {
    "notarize": {
      "enabled": true,
      "identity": "Developer ID"
    },
    "compression": {
      "level": "high"
    }
  }
}

13. 总结

Installer Builder 是一个灵活、可扩展的安装包构建工具,支持多平台、多架构和多种包格式。它的模块化设计使得添加新的平台和包类型变得简单,插件系统允许进一步扩展功能。

主要特点包括:

  1. 支持 Windows 和 Linux 平台
  2. 支持 MSI、DEB、RPM 和 ZIP 包格式
  3. 支持多架构构建
  4. 基于配置文件的声明式定义
  5. 支持安装前后脚本
  6. 支持安装包升级
  7. 插件系统用于扩展功能