// 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 }