Files
DevPack/internal/platform/linux.go
2026-03-06 11:59:00 +08:00

174 lines
4.3 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 platform
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"github.com/user/devpack/internal/logging"
)
// LinuxPlatform Linux 平台实现
type LinuxPlatform struct {
homeDir string
}
// NewLinuxPlatform 创建 Linux 平台实例
func NewLinuxPlatform() *LinuxPlatform {
home, _ := os.UserHomeDir()
return &LinuxPlatform{homeDir: home}
}
func (p *LinuxPlatform) OS() string { return "linux" }
func (p *LinuxPlatform) Arch() string { return "amd64" } // TODO: 正确检测架构
func (p *LinuxPlatform) HomeDir() string { return p.homeDir }
func (p *LinuxPlatform) ConfigDir() string {
if dir := os.Getenv("XDG_CONFIG_HOME"); dir != "" {
return dir
}
return p.homeDir + "/.config"
}
func (p *LinuxPlatform) DataDir() string {
if dir := os.Getenv("XDG_DATA_HOME"); dir != "" {
return dir
}
return p.homeDir + "/.local/share"
}
func (p *LinuxPlatform) GetEnvVar(key string) string {
return os.Getenv(key)
}
func (p *LinuxPlatform) SetEnvVar(ctx context.Context, key, value string) error {
// TODO: 写入 Shell 配置文件以持久化
return os.Setenv(key, value)
}
func (p *LinuxPlatform) AddToPath(ctx context.Context, dir string) error {
// TODO: 添加到 Shell 配置文件
return nil
}
func (p *LinuxPlatform) IsAdmin() bool {
return os.Geteuid() == 0
}
func (p *LinuxPlatform) PackageManagers() []string {
var pms []string
if _, err := exec.LookPath("apt"); err == nil {
pms = append(pms, "apt")
}
if _, err := exec.LookPath("dnf"); err == nil {
pms = append(pms, "dnf")
}
if _, err := exec.LookPath("yum"); err == nil {
pms = append(pms, "yum")
}
if _, err := exec.LookPath("pacman"); err == nil {
pms = append(pms, "pacman")
}
if _, err := exec.LookPath("snap"); err == nil {
pms = append(pms, "snap")
}
return pms
}
func (p *LinuxPlatform) DefaultShell() string {
shell := os.Getenv("SHELL")
if shell != "" {
return shell
}
return "/bin/bash"
}
// InstallFont 安装字体到用户级字体目录并刷新字体缓存
// 支持 .ttf (TrueType) 和 .otf (OpenType) 格式
func (p *LinuxPlatform) InstallFont(ctx context.Context, fontPath string) error {
log := logging.G()
// 验证源字体文件是否存在且可访问
info, err := os.Stat(fontPath)
if err != nil {
log.Errorf("无法访问字体文件: %v", err)
return fmt.Errorf("无法访问字体文件: %w", err)
}
if info.IsDir() {
return fmt.Errorf("字体路径是目录而非文件: %s", fontPath)
}
// 检查字体格式是否受支持
fontName := filepath.Base(fontPath)
ext := filepath.Ext(fontName)
if ext != ".ttf" && ext != ".otf" {
log.Errorf("不支持的字体格式: %s", ext)
return fmt.Errorf("不支持的字体格式: %s仅支持 .ttf 和 .otf", ext)
}
// 用户级字体目录: ~/.local/share/fonts/
destDir := filepath.Join(p.homeDir, ".local", "share", "fonts")
log.Debugf("正在安装字体: %s 到 %s", fontPath, destDir)
// 确保目标目录存在
if err := os.MkdirAll(destDir, 0755); err != nil {
return fmt.Errorf("创建字体目录失败: %w", err)
}
// 检查字体是否已安装
destPath := filepath.Join(destDir, fontName)
if _, err := os.Stat(destPath); err == nil {
log.Infof("字体已存在,跳过安装: %s", destPath)
return nil
}
// 复制字体文件到目标路径
if err := linuxCopyFile(fontPath, destPath); err != nil {
return fmt.Errorf("复制字体文件失败: %w", err)
}
// 刷新字体缓存
if _, err := exec.LookPath("fc-cache"); err == nil {
cmd := exec.CommandContext(ctx, "fc-cache", "-f", destDir)
if out, err := cmd.CombinedOutput(); err != nil {
log.Warnf("刷新字体缓存失败: %s, %v", string(out), err)
// 字体文件已复制成功,缓存刷新失败不是致命错误
}
} else {
log.Warnf("未找到 fc-cache 命令,字体缓存未刷新,可能需要重新登录后生效")
}
log.Infof("字体安装成功: %s", fontName)
return nil
}
// linuxCopyFile 复制文件,失败时自动清理目标文件
func linuxCopyFile(src, dst string) error {
input, err := os.Open(src)
if err != nil {
return err
}
defer input.Close()
output, err := os.Create(dst)
if err != nil {
return err
}
_, err = io.Copy(output, input)
closeErr := output.Close()
if err != nil {
os.Remove(dst)
return err
}
if closeErr != nil {
os.Remove(dst)
return closeErr
}
return nil
}