installerbuilder/internal/builder/linux/deb.go

291 lines
7.5 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 linux 提供Linux平台安装包构建功能
package linux
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"
)
// DEBBuilder 是Linux DEB安装包构建器
type DEBBuilder struct {
config *config.Config
outputDir string
}
// 确保DEBBuilder实现了Builder接口
var _ builder.Builder = (*DEBBuilder)(nil)
// 注册构建器
func init() {
builder.RegisterBuilder("linux-deb", func(cfg *config.Config, outputDir string) builder.Builder {
return NewDEBBuilder(cfg, outputDir)
})
}
// NewDEBBuilder 创建一个新的DEB构建器
func NewDEBBuilder(cfg *config.Config, outputDir string) *DEBBuilder {
return &DEBBuilder{
config: cfg,
outputDir: outputDir,
}
}
// Name 返回构建器名称
func (b *DEBBuilder) Name() string {
return "Linux DEB Builder"
}
// SupportedPlatforms 返回支持的平台列表
func (b *DEBBuilder) SupportedPlatforms() []string {
return []string{"linux"}
}
// SupportedFormats 返回支持的格式列表
func (b *DEBBuilder) SupportedFormats() []string {
return []string{"deb"}
}
// Build 构建DEB安装包
func (b *DEBBuilder) Build() error {
logger.Info("开始构建Linux DEB安装包")
// 创建临时工作目录
workDir, err := os.MkdirTemp("", "installer-builder-deb-*")
if err != nil {
return fmt.Errorf("创建临时工作目录失败: %w", err)
}
defer os.RemoveAll(workDir)
logger.Debugf("使用临时工作目录: %s", workDir)
// 创建DEB包结构
if err := b.createDebStructure(workDir); err != nil {
return fmt.Errorf("创建DEB包结构失败: %w", err)
}
// 复制文件到临时目录
if err := b.copyFiles(workDir); err != nil {
return fmt.Errorf("复制文件失败: %w", err)
}
// 创建控制文件
if err := b.createControlFile(workDir); err != nil {
return fmt.Errorf("创建控制文件失败: %w", err)
}
// 创建安装脚本
if err := b.createScripts(workDir); err != nil {
return fmt.Errorf("创建安装脚本失败: %w", err)
}
// 构建DEB包
debFile := filepath.Join(b.outputDir, fmt.Sprintf("%s_%s_amd64.deb", b.config.Name, b.config.Version))
if err := b.buildDeb(workDir, debFile); err != nil {
return fmt.Errorf("构建DEB包失败: %w", err)
}
logger.Infof("成功构建DEB安装包: %s", debFile)
return nil
}
// createDebStructure 创建DEB包结构
func (b *DEBBuilder) createDebStructure(workDir string) error {
// 创建DEBIAN目录
debianDir := filepath.Join(workDir, "DEBIAN")
if err := os.MkdirAll(debianDir, 0755); err != nil {
return fmt.Errorf("创建DEBIAN目录失败: %w", err)
}
// 创建安装目录
installDir := filepath.Join(workDir, "usr", "local", "bin")
if err := os.MkdirAll(installDir, 0755); err != nil {
return fmt.Errorf("创建安装目录失败: %w", err)
}
// 创建文档目录
docDir := filepath.Join(workDir, "usr", "share", "doc", b.config.Name)
if err := os.MkdirAll(docDir, 0755); err != nil {
return fmt.Errorf("创建文档目录失败: %w", err)
}
return nil
}
// copyFiles 复制文件到临时目录
func (b *DEBBuilder) copyFiles(workDir string) error {
// 这里应该实现文件复制逻辑
// 实际应用中,应该根据配置复制文件到临时目录
logger.Debug("复制文件到临时目录")
return nil
}
// createControlFile 创建控制文件
func (b *DEBBuilder) createControlFile(workDir string) error {
controlFile := filepath.Join(workDir, "DEBIAN", "control")
// 准备依赖项列表
var depends string
if len(b.config.Platforms.Linux.Deb.Depends) > 0 {
depends = strings.Join(b.config.Platforms.Linux.Deb.Depends, ", ")
} else {
depends = ""
}
// 准备推荐项列表
var recommends string
if len(b.config.Platforms.Linux.Deb.Recommends) > 0 {
recommends = strings.Join(b.config.Platforms.Linux.Deb.Recommends, ", ")
} else {
recommends = ""
}
// 准备建议项列表
var suggests string
if len(b.config.Platforms.Linux.Deb.Suggests) > 0 {
suggests = strings.Join(b.config.Platforms.Linux.Deb.Suggests, ", ")
} else {
suggests = ""
}
// 准备冲突项列表
var conflicts string
if len(b.config.Platforms.Linux.Deb.Conflicts) > 0 {
conflicts = strings.Join(b.config.Platforms.Linux.Deb.Conflicts, ", ")
} else {
conflicts = ""
}
// 准备替换项列表
var replaces string
if len(b.config.Platforms.Linux.Deb.Replaces) > 0 {
replaces = strings.Join(b.config.Platforms.Linux.Deb.Replaces, ", ")
} else {
replaces = ""
}
// 创建控制文件内容
content := fmt.Sprintf(`Package: %s
Version: %s
Section: %s
Priority: %s
Architecture: %s
Maintainer: %s
Description: %s
`,
b.config.Name,
b.config.Version,
b.config.Platforms.Linux.Deb.Section,
b.config.Platforms.Linux.Deb.Priority,
b.config.Platforms.Linux.Deb.Architecture,
b.config.Author,
b.config.Description)
// 添加可选字段
if depends != "" {
content += fmt.Sprintf("Depends: %s\n", depends)
}
if recommends != "" {
content += fmt.Sprintf("Recommends: %s\n", recommends)
}
if suggests != "" {
content += fmt.Sprintf("Suggests: %s\n", suggests)
}
if conflicts != "" {
content += fmt.Sprintf("Conflicts: %s\n", conflicts)
}
if replaces != "" {
content += fmt.Sprintf("Replaces: %s\n", replaces)
}
// 写入控制文件
return os.WriteFile(controlFile, []byte(content), 0644)
}
// createScripts 创建安装脚本
func (b *DEBBuilder) createScripts(workDir string) error {
// 脚本类型到文件名的映射
scriptFiles := map[string]string{
"preinstall": "preinst",
"postinstall": "postinst",
"preuninstall": "prerm",
"postuninstall": "postrm",
}
// 遍历配置中的脚本
for _, script := range b.config.Contents.Scripts {
// 检查是否是DEB支持的脚本类型
filename, ok := scriptFiles[script.Type]
if !ok {
logger.Warnf("跳过不支持的脚本类型: %s", script.Type)
continue
}
// 脚本文件路径
scriptPath := filepath.Join(workDir, "DEBIAN", filename)
// 获取脚本内容
var content string
if script.Content != "" {
content = script.Content
} else if script.Source != "" {
// 从源文件读取脚本内容
data, err := os.ReadFile(script.Source)
if err != nil {
return fmt.Errorf("读取脚本源文件失败: %w", err)
}
content = string(data)
} else {
logger.Warnf("跳过空脚本: %s", script.Type)
continue
}
// 确保脚本以#!/bin/sh开头
if !strings.HasPrefix(content, "#!") {
content = "#!/bin/sh\n" + content
}
// 写入脚本文件
if err := os.WriteFile(scriptPath, []byte(content), 0755); err != nil {
return fmt.Errorf("写入脚本文件失败: %w", err)
}
logger.Debugf("创建脚本文件: %s", scriptPath)
}
return nil
}
// buildDeb 构建DEB包
func (b *DEBBuilder) buildDeb(workDir, outputFile string) error {
// 检查是否安装了dpkg-deb
dpkgDeb, err := exec.LookPath("dpkg-deb")
if err != nil {
return fmt.Errorf("未找到dpkg-deb工具请确保已安装dpkg-deb并添加到PATH中")
}
// 确保输出目录存在
if err := os.MkdirAll(filepath.Dir(outputFile), 0755); err != nil {
return fmt.Errorf("创建输出目录失败: %w", err)
}
// 构建命令
cmd := exec.Command(dpkgDeb, "--build", workDir, outputFile)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// 执行命令
logger.Debugf("执行命令: %s", strings.Join(cmd.Args, " "))
if err := cmd.Run(); err != nil {
return fmt.Errorf("执行dpkg-deb命令失败: %w", err)
}
return nil
}