Skip to content

fix(grub-theme): Fix incomplete display of GRUB theme menu text on arm64, loongarch64, and sw64 architectures#179

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
electricface:swt/fix-grub-theme
Mar 3, 2026
Merged

fix(grub-theme): Fix incomplete display of GRUB theme menu text on arm64, loongarch64, and sw64 architectures#179
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
electricface:swt/fix-grub-theme

Conversation

@electricface
Copy link
Member

@electricface electricface commented Feb 27, 2026

- Add support for V25 GRUB theme adjustments
- Migrate the original deepin theme resources to the deepin-v20
directory
- Copy a theme from deepin-fallback to the deepin theme
- Upgrade the theme adjustment tool version from 18 to 19
- Specifically increase the menu width when GFXMODE is set to
1024x768

---

fix(grub-theme): 修复arm64,loongarch64,sw64架构的
GRUB主题菜单文字显示不全

- 新增 V25 GRUB 主题调整支持
- 将原有的 deepin 主题资源迁移到 deepin-v20 目录
- 从 deepin-fallback 复制一份主题到 deepin 主题
- 主题调整工具版本号从 18 升级到 19
- 在GFXMODE为1024x7682,特别地增加启动菜单宽度

Log: 修复arm64,loongarch64,sw64架构的GRUB主题菜单文字显示不全
Influence: GRUB主题
PMS: BUG-277733, BUG-291909

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @electricface, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@electricface electricface force-pushed the swt/fix-grub-theme branch 7 times, most recently from 76a14a4 to cae0d67 Compare March 2, 2026 10:03
@electricface electricface changed the title feat(grub-theme): 优化并新增Deepin grub主题支持 fix(grub-theme): Fix incomplete display of GRUB theme menu text on arm64, loongarch64, and sw64 architectures Mar 2, 2026
@electricface electricface marked this pull request as ready for review March 2, 2026 10:23
arm64, loongarch64, and sw64 architectures

- Add support for V25 GRUB theme adjustments
- Migrate the original deepin theme resources to the deepin-v20
directory
- Copy a theme from deepin-fallback to the deepin theme
- Upgrade the theme adjustment tool version from 18 to 19
- Specifically increase the menu width when GFXMODE is set to
1024x768

---

fix(grub-theme): 修复arm64,loongarch64,sw64架构的
GRUB主题菜单文字显示不全

- 新增 V25 GRUB 主题调整支持
- 将原有的 deepin 主题资源迁移到 deepin-v20 目录
- 从 deepin-fallback 复制一份主题到 deepin 主题
- 主题调整工具版本号从 18 升级到 19
- 在GFXMODE为1024x7682,特别地增加启动菜单宽度

Log: 修复arm64,loongarch64,sw64架构的GRUB主题菜单文字显示不全
Influence: GRUB主题
PMS: BUG-277733, BUG-291909
@deepin-ci-robot
Copy link

deepin pr auto review

Git Diff 代码审查报告

总体概述

这个 diff 主要对 GRUB 主题调整工具进行了重大更新,包括:

  1. 更新了版权年份至 2026 年
  2. 引入了新版本的主题处理逻辑 (V25)
  3. 改进了 GRUB 参数加载机制,支持从多个配置文件读取
  4. 重构了主题文件结构,分离了 V20 和 V25 版本的主题资源

详细审查意见

1. 语法逻辑

1.1 GRUB 参数加载逻辑改进

位置: util.go 中的 loadGrubParamsreadGrubParamsFile 函数

改进点:

  • loadGrubParams 从接收单个文件路径改为接收文件路径数组,支持从多个配置文件读取参数
  • 新增 readGrubParamsFile 函数处理单个配置文件读取
  • 使用 bufio.Scanner 替代之前的 kv.NewReader,提高了代码的可读性和可维护性

建议:

// 当前实现
func loadGrubParams(grubParamsFilePaths []string) map[string]string {
    params := make(map[string]string)
    
    // First read the main configuration file
    for _, grubParamsFilePath := range grubParamsFilePaths {
        if err := readGrubParamsFile(grubParamsFilePath, params); err != nil {
            logger.Warningf("Failed to read grub params file %s: %v", grubParamsFilePath, err)
        }
    }
    
    return params
}

// 建议改进:添加注释说明参数合并规则(后读取的文件会覆盖先读取的参数)
func loadGrubParams(grubParamsFilePaths []string) map[string]string {
    // 参数合并规则:后读取的文件中的参数会覆盖先读取的文件中的同名参数
    // 这与GRUB实际行为一致,后加载的配置文件优先级更高
    params := make(map[string]string)
    
    for _, grubParamsFilePath := range grubParamsFilePaths {
        if err := readGrubParamsFile(grubParamsFilePath, params); err != nil {
            logger.Warningf("Failed to read grub params file %s: %v", grubParamsFilePath, err)
        }
    }
    
    return params
}

1.2 getScreenSizeFromGrubParams 函数签名变更

位置: main.go 中的 getScreenSizeFromGrubParams 函数

改进点:

  • 函数签名从接收单个文件路径改为接收文件路径数组
  • 调用 loadGrubParams 时不再处理错误,因为新实现不会返回错误

建议:

// 当前实现
func getScreenSizeFromGrubParams(grubParamsFilePaths []string) (w, h int, err error) {
    params := loadGrubParams(grubParamsFilePaths)
    
    w, h, err = parseResolution(getGfxMode(params))
    if err != nil {
        return
    }
    return
}

// 建议改进:添加参数验证
func getScreenSizeFromGrubParams(grubParamsFilePaths []string) (w, h int, err error) {
    if len(grubParamsFilePaths) == 0 {
        return 0, 0, fmt.Errorf("no grub params files provided")
    }
    
    params := loadGrubParams(grubParamsFilePaths)
    
    w, h, err = parseResolution(getGfxMode(params))
    if err != nil {
        return
    }
    return
}

2. 代码质量

2.1 新增 adjustThemeNormalV25 函数

位置: main.go 中的 adjustThemeNormalV25 函数

改进点:

  • 新增了 V25 版本的主题处理逻辑
  • 代码结构与 adjustThemeNormal 类似,但使用了不同的背景图片加载方式

建议:

// 建议提取公共逻辑,减少代码重复
// 可以将公共部分提取为辅助函数
func prepareThemeOutputDir(themeInputDir, themeOutputDir string) error {
    cleanupThemeOutputDir(themeOutputDir)
    err := os.MkdirAll(themeOutputDir, 0755)
    if err != nil {
        return err
    }
    copyThemeFiles(themeInputDir, themeOutputDir)
    return nil
}

func adjustThemeNormalV25() error {
    themeInputDir := filepath.Join(optThemeInputDir, themeNameNormal)
    themeOutputDir := filepath.Join(optThemeOutputDir, themeNameNormal)
    
    // 使用提取的公共函数
    if err := prepareThemeOutputDir(themeInputDir, themeOutputDir); err != nil {
        return err
    }
    
    // 其余特定逻辑...
}

2.2 新增 adjustBootMenuV25 函数

位置: main.go 中的 adjustBootMenuV25 函数

改进点:

  • 添加了针对特定分辨率 (1024x768) 的菜单宽度调整逻辑

建议:

// 当前实现
func adjustBootMenuV25(comp *tt.Component, width, height int) {
    if width == 1024 && height == 768 {
        // halfWidthPercent represents half of the boot menu width percentage.
        // The boot menu is centered, so width = halfWidthPercent * 2, left = 50% - halfWidthPercent,
        halfWidthPercent := 22
        comp.SetProp("width", tt.RelNum(halfWidthPercent*2))
        comp.SetProp("left", tt.RelNum(50-halfWidthPercent))
    }
}

// 建议改进:添加更多分辨率支持,使函数更通用
func adjustBootMenuV25(comp *tt.Component, width, height int) {
    var halfWidthPercent int
    
    // 根据不同分辨率设置不同的菜单宽度
    switch {
    case width == 1024 && height == 768:
        halfWidthPercent = 22
    case width == 1920 && height == 1080:
        halfWidthPercent = 20
    case width == 1366 && height == 768:
        halfWidthPercent = 21
    default:
        // 默认值,可根据需要调整
        halfWidthPercent = 22
    }
    
    // halfWidthPercent represents half of the boot menu width percentage.
    // The boot menu is centered, so width = halfWidthPercent * 2, left = 50% - halfWidthPercent
    comp.SetProp("width", tt.RelNum(halfWidthPercent*2))
    comp.SetProp("left", tt.RelNum(50-halfWidthPercent))
}

2.3 新增 FindComponentByType 方法

位置: grub_theme/themetxt/theme.go 中的 FindComponentByType 方法

改进点:

  • 添加了根据类型查找组件的功能,使代码更加模块化

建议:

// 当前实现
// FindComponentByType finds the first component by component type
func (t *Theme) FindComponentByType(compType string) *Component {
    for _, comp := range t.Components {
        if comp.Type == compType {
            return comp
        }
    }
    return nil
}

// 建议改进:添加错误处理和日志记录
// FindComponentByType finds the first component by component type
func (t *Theme) FindComponentByType(compType string) (*Component, error) {
    if t == nil {
        return nil, fmt.Errorf("theme is nil")
    }
    
    for _, comp := range t.Components {
        if comp.Type == compType {
            return comp, nil
        }
    }
    return nil, fmt.Errorf("component with type %s not found", compType)
}

3. 代码性能

3.1 GRUB 参数文件读取优化

位置: util.go 中的 readGrubParamsFile 函数

改进点:

  • 使用 bufio.Scanner 逐行读取文件,内存效率较高

建议:

// 当前实现
func readGrubParamsFile(filePath string, params map[string]string) error {
    f, err := os.Open(filePath)
    if err != nil {
        if os.IsNotExist(err) {
            return nil
        }
        return err
    }
    defer func() {
        _ = f.Close()
    }()
    
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        line := strings.TrimSpace(scanner.Text())
        // Skip empty lines and comment lines
        if line == "" || strings.HasPrefix(line, "#") {
            continue
        }
        // Find the position of the first equal sign
        eqIdx := strings.Index(line, "=")
        if eqIdx == -1 {
            // Not in key=value format, skip
            continue
        }
        key := strings.TrimSpace(line[:eqIdx])
        value := strings.TrimSpace(line[eqIdx+1:])
        if key == "" {
            continue
        }
        params[key] = value
    }
    return scanner.Err()
}

// 建议改进:增加缓冲区大小,提高大文件读取性能
func readGrubParamsFile(filePath string, params map[string]string) error {
    f, err := os.Open(filePath)
    if err != nil {
        if os.IsNotExist(err) {
            return nil
        }
        return err
    }
    defer func() {
        _ = f.Close()
    }()
    
    // 使用更大的缓冲区,提高读取性能
    scanner := bufio.NewScanner(f)
    const maxCapacity = 1024 * 1024 // 1MB
    buf := make([]byte, maxCapacity)
    scanner.Buffer(buf, maxCapacity)
    
    for scanner.Scan() {
        line := strings.TrimSpace(scanner.Text())
        // Skip empty lines and comment lines
        if line == "" || strings.HasPrefix(line, "#") {
            continue
        }
        // Find the position of the first equal sign
        eqIdx := strings.Index(line, "=")
        if eqIdx == -1 {
            // Not in key=value format, skip
            continue
        }
        key := strings.TrimSpace(line[:eqIdx])
        value := strings.TrimSpace(line[eqIdx+1:])
        if key == "" {
            continue
        }
        params[key] = value
    }
    return scanner.Err()
}

4. 代码安全

4.1 文件路径处理

位置: main.goutil.go 中的多处文件路径处理

改进点:

  • 使用 filepath.Join 构建路径,提高了跨平台兼容性

建议:

// 建议添加路径验证函数,防止路径遍历攻击
func validatePath(basePath, requestedPath string) (string, error) {
    // 获取绝对路径
    absBasePath, err := filepath.Abs(basePath)
    if err != nil {
        return "", err
    }
    
    absRequestedPath, err := filepath.Abs(requestedPath)
    if err != nil {
        return "", err
    }
    
    // 确保请求的路径在基础路径下
    if !strings.HasPrefix(absRequestedPath, absBasePath) {
        return "", fmt.Errorf("requested path %s is outside base path %s", requestedPath, basePath)
    }
    
    return absRequestedPath, nil
}

// 使用示例
func adjustThemeNormalV25() error {
    themeInputDir := filepath.Join(optThemeInputDir, themeNameNormal)
    themeOutputDir := filepath.Join(optThemeOutputDir, themeNameNormal)
    
    // 验证路径
    validatedInputDir, err := validatePath(optThemeInputDir, themeInputDir)
    if err != nil {
        return fmt.Errorf("invalid theme input directory: %v", err)
    }
    
    validatedOutputDir, err := validatePath(optThemeOutputDir, themeOutputDir)
    if err != nil {
        return fmt.Errorf("invalid theme output directory: %v", err)
    }
    
    // 使用验证后的路径...
}

4.2 文件操作安全性

位置: main.go 中的 adjustThemeNormalV25 函数

改进点:

  • 使用 os.Create 创建文件,但没有检查文件是否已存在

建议:

// 当前实现
themeOutput := filepath.Join(themeOutputDir, "theme.txt")
themeOutputFh, err := os.Create(themeOutput)
if err != nil {
    return err
}

// 建议改进:添加文件存在性检查和权限设置
themeOutput := filepath.Join(themeOutputDir, "theme.txt")
// 检查文件是否已存在
if _, err := os.Stat(themeOutput); err == nil {
    // 文件已存在,先备份
    backupPath := themeOutput + ".bak"
    if err := os.Rename(themeOutput, backupPath); err != nil {
        return fmt.Errorf("failed to backup existing theme file: %v", err)
    }
}

// 创建文件并设置适当的权限
themeOutputFh, err := os.OpenFile(themeOutput, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
    return fmt.Errorf("failed to create theme file: %v", err)
}

5. 测试相关

5.1 测试用例更新

位置: adjust_grub_theme_test.go 中的 TestGetScreenSizeFromGrubParams 测试函数

改进点:

  • 更新了测试用例以支持新的多文件参数加载机制
  • 添加了对新增测试数据文件的检查

建议:

// 当前实现
func (s *su) TestGetScreenSizeFromGrubParams() {
    require.FileExists(s.T(), "testdata/grub")
    require.FileExists(s.T(), "testdata/grub.d/00_test")
    require.FileExists(s.T(), "testdata/grub.d/99_local")
    w, h, err := getScreenSizeFromGrubParams([]string{
        "testdata/grub",
        "testdata/grub.d/00_test",
        "testdata/grub.d/99_local",
    })
    assert.NoError(s.T(), err)
    assert.Equal(s.T(), 1024, w)
    assert.Equal(s.T(), 768, h)
}

// 建议改进:添加更多测试用例,覆盖不同场景
func (s *su) TestGetScreenSizeFromGrubParams() {
    // 测试用例1:所有文件都存在
    s.Run("AllFilesExist", func() {
        require.FileExists(s.T(), "testdata/grub")
        require.FileExists(s.T(), "testdata/grub.d/00_test")
        require.FileExists(s.T(), "testdata/grub.d/99_local")
        w, h, err := getScreenSizeFromGrubParams([]string{
            "testdata/grub",
            "testdata/grub.d/00_test",
            "testdata/grub.d/99_local",
        })
        assert.NoError(s.T(), err)
        assert.Equal(s.T(), 1024, w)
        assert.Equal(s.T(), 768, h)
    })
    
    // 测试用例2:部分文件不存在
    s.Run("PartialFilesExist", func() {
        require.FileExists(s.T(), "testdata/grub")
        w, h, err := getScreenSizeFromGrubParams([]string{
            "testdata/grub",
            "testdata/nonexistent_file",
        })
        assert.NoError(s.T(), err)
        // 根据testdata/grub的内容断言结果
    })
    
    // 测试用例3:空文件列表
    s.Run("EmptyFileList", func() {
        w, h, err := getScreenSizeFromGrubParams([]string{})
        assert.Error(s.T(), err)
    })
    
    // 测试用例4:参数覆盖测试
    s.Run("ParamOverride", func() {
        // 测试后读取的文件参数是否覆盖先读取的文件参数
        w, h, err := getScreenSizeFromGrubParams([]string{
            "testdata/grub",
            "testdata/grub.d/00_test", // 包含 1920x1080
            "testdata/grub.d/99_local", // 包含 1024x768
        })
        assert.NoError(s.T(), err)
        // 应该使用99_local中的值
        assert.Equal(s.T(), 1024, w)
        assert.Equal(s.T(), 768, h)
    })
}

总结

这个 diff 对 GRUB 主题调整工具进行了重大更新,主要改进包括:

  1. 功能增强:支持从多个配置文件读取 GRUB 参数,符合 GRUB 实际行为
  2. 版本迭代:引入了 V25 版本的主题处理逻辑,支持更灵活的主题配置
  3. 代码重构:改进了参数加载逻辑,提高了代码可读性和可维护性
  4. 测试更新:更新了测试用例以支持新的功能

建议在后续开发中:

  1. 添加更多错误处理和日志记录
  2. 提取公共逻辑,减少代码重复
  3. 增强文件操作的安全性
  4. 扩展测试用例,覆盖更多边界情况

整体来看,这是一个质量较高的代码更新,主要功能实现合理,但在错误处理、代码复用和安全性方面还有改进空间。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: electricface, fly602

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@electricface
Copy link
Member Author

/forcemerge

@deepin-bot deepin-bot bot merged commit 8e0fda0 into linuxdeepin:master Mar 3, 2026
18 checks passed
@electricface electricface deleted the swt/fix-grub-theme branch March 3, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants