installerbuilder/internal/builder/windows/msi.go

198 lines
5.7 KiB
Go
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.

// 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(`<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="%s"
Language="1033"
Version="%s"
Manufacturer="%s"
UpgradeCode="%s">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Description="%s" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="Main Product" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="%s">
<!-- 组件将在这里定义 -->
</Directory>
</Directory>
</Directory>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- 组件将在这里定义 -->
</ComponentGroup>
</Product>
</Wix>`,
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
}