// Package windows 提供Windows平台安装包构建功能 package windows import ( "fmt" "os" "os/exec" "path/filepath" "strings" "git.kingecg.top/kingecg/installerbuilder/internal/builder" "git.kingecg.top/kingecg/installerbuilder/internal/config" "git.kingecg.top/kingecg/installerbuilder/internal/logger" ) // MSIBuilder 是Windows MSI安装包构建器 type MSIBuilder struct { config *config.Config outputDir string } // 确保MSIBuilder实现了Builder接口 var _ builder.Builder = (*MSIBuilder)(nil) // 注册构建器 func init() { builder.RegisterBuilder("windows-msi", func(cfg *config.Config, outputDir string) builder.Builder { return NewMSIBuilder(cfg, outputDir) }) } // NewMSIBuilder 创建一个新的MSI构建器 func NewMSIBuilder(cfg *config.Config, outputDir string) *MSIBuilder { return &MSIBuilder{ config: cfg, outputDir: outputDir, } } // Name 返回构建器名称 func (b *MSIBuilder) Name() string { return "Windows MSI Builder" } // SupportedPlatforms 返回支持的平台列表 func (b *MSIBuilder) SupportedPlatforms() []string { return []string{"windows"} } // SupportedFormats 返回支持的格式列表 func (b *MSIBuilder) SupportedFormats() []string { return []string{"msi"} } // Build 构建MSI安装包 func (b *MSIBuilder) Build() error { logger.Info("开始构建Windows MSI安装包") // 创建临时工作目录 workDir, err := os.MkdirTemp("", "installer-builder-msi-*") if err != nil { return fmt.Errorf("创建临时工作目录失败: %w", err) } defer os.RemoveAll(workDir) logger.Debugf("使用临时工作目录: %s", workDir) // 创建WiX源文件 wixFile := filepath.Join(workDir, "installer.wxs") if err := b.createWixSource(wixFile); err != nil { return fmt.Errorf("创建WiX源文件失败: %w", err) } // 复制文件到临时目录 if err := b.copyFiles(workDir); err != nil { return fmt.Errorf("复制文件失败: %w", err) } // 编译WiX源文件 objFile := filepath.Join(workDir, "installer.wixobj") if err := b.compileWixSource(wixFile, objFile); err != nil { return fmt.Errorf("编译WiX源文件失败: %w", err) } // 链接生成MSI msiFile := filepath.Join(b.outputDir, fmt.Sprintf("%s-%s.msi", b.config.Name, b.config.Version)) if err := b.linkMsi(objFile, msiFile); err != nil { return fmt.Errorf("链接MSI文件失败: %w", err) } logger.Infof("成功构建MSI安装包: %s", msiFile) return nil } // createWixSource 创建WiX源文件 func (b *MSIBuilder) createWixSource(outputFile string) error { // 这里是一个简化的WiX源文件生成示例 // 实际应用中,应该根据配置生成更复杂的WiX源文件 content := fmt.Sprintf(` `, b.config.Name, b.config.Version, b.config.Platforms.Windows.Msi.Manufacturer, b.config.Platforms.Windows.Msi.UpgradeCode, b.config.Description, b.config.Platforms.Windows.Msi.InstallDir) return os.WriteFile(outputFile, []byte(content), 0644) } // copyFiles 复制文件到临时目录 func (b *MSIBuilder) copyFiles(workDir string) error { // 这里应该实现文件复制逻辑 // 实际应用中,应该根据配置复制文件到临时目录 logger.Debug("复制文件到临时目录") return nil } // compileWixSource 编译WiX源文件 func (b *MSIBuilder) compileWixSource(sourceFile, outputFile string) error { // 检查是否安装了WiX工具集 candle, err := exec.LookPath("candle") if err != nil { return fmt.Errorf("未找到WiX Toolset的candle工具,请确保已安装WiX Toolset并添加到PATH中") } // 构建命令 cmd := exec.Command(candle, "-nologo", "-arch", "x64", "-out", outputFile, sourceFile) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr // 执行命令 logger.Debugf("执行命令: %s", strings.Join(cmd.Args, " ")) if err := cmd.Run(); err != nil { return fmt.Errorf("执行candle命令失败: %w", err) } return nil } // linkMsi 链接生成MSI func (b *MSIBuilder) linkMsi(objFile, msiFile string) error { // 检查是否安装了WiX工具集 light, err := exec.LookPath("light") if err != nil { return fmt.Errorf("未找到WiX Toolset的light工具,请确保已安装WiX Toolset并添加到PATH中") } // 确保输出目录存在 if err := os.MkdirAll(filepath.Dir(msiFile), 0755); err != nil { return fmt.Errorf("创建输出目录失败: %w", err) } // 构建命令 cmd := exec.Command(light, "-nologo", "-ext", "WixUIExtension", "-out", msiFile, objFile) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr // 执行命令 logger.Debugf("执行命令: %s", strings.Join(cmd.Args, " ")) if err := cmd.Run(); err != nil { return fmt.Errorf("执行light命令失败: %w", err) } return nil }