2
0
mirror of https://github.com/acepanel/helper.git synced 2026-02-04 01:47:16 +08:00
Files
helper/internal/system/package.go
2026-01-26 17:50:05 +08:00

231 lines
6.7 KiB
Go

package system
import (
"context"
"fmt"
"os"
"strings"
"github.com/acepanel/helper/pkg/i18n"
"github.com/acepanel/helper/pkg/types"
)
// PackageManager 包管理器接口
type PackageManager interface {
// UpdateCache 更新软件源缓存
UpdateCache(ctx context.Context) error
// Install 安装软件包
Install(ctx context.Context, packages ...string) error
// Remove 移除软件包
Remove(ctx context.Context, packages ...string) error
// IsInstalled 检查是否已安装
IsInstalled(ctx context.Context, pkg string) bool
// SetMirror 设置镜像源
SetMirror(ctx context.Context, inChina bool) error
// EnableEPEL 启用EPEL源 (仅RHEL系)
EnableEPEL(ctx context.Context, inChina bool) error
}
// NewPackageManager 根据OS类型创建包管理器
func NewPackageManager(osType types.OSType, executor Executor) PackageManager {
switch osType {
case types.OSRHEL:
return &dnfManager{executor: executor}
case types.OSDebian, types.OSUbuntu:
return &aptManager{executor: executor, osType: osType}
default:
return nil
}
}
// dnfManager DNF包管理器 (RHEL系)
type dnfManager struct {
executor Executor
}
func (m *dnfManager) UpdateCache(ctx context.Context) error {
result, err := m.executor.Run(ctx, "dnf", "makecache", "-y")
if err != nil {
return err
}
if result.ExitCode != 0 {
return fmt.Errorf("%s: %s", i18n.T.Get("dnf makecache failed"), result.Stderr)
}
return nil
}
func (m *dnfManager) Install(ctx context.Context, packages ...string) error {
args := append([]string{"install", "-y"}, packages...)
result, err := m.executor.Run(ctx, "dnf", args...)
if err != nil {
return err
}
if result.ExitCode != 0 {
return fmt.Errorf("%s: %s", i18n.T.Get("dnf install failed"), result.Stderr)
}
return nil
}
func (m *dnfManager) Remove(ctx context.Context, packages ...string) error {
args := append([]string{"remove", "-y"}, packages...)
result, err := m.executor.Run(ctx, "dnf", args...)
if err != nil {
return err
}
if result.ExitCode != 0 {
return fmt.Errorf("%s: %s", i18n.T.Get("dnf remove failed"), result.Stderr)
}
return nil
}
func (m *dnfManager) IsInstalled(ctx context.Context, pkg string) bool {
result, _ := m.executor.Run(ctx, "rpm", "-q", pkg)
return result != nil && result.ExitCode == 0
}
func (m *dnfManager) SetMirror(ctx context.Context, inChina bool) error {
if !inChina {
return nil
}
// Rocky Linux
m.sedReplace("/etc/yum.repos.d/[Rr]ocky*.repo",
"s|^mirrorlist=|#mirrorlist=|g",
"s|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.tencent.com/rocky|g",
)
// AlmaLinux
m.sedReplace("/etc/yum.repos.d/[Aa]lmalinux*.repo",
"s|^mirrorlist=|#mirrorlist=|g",
"s|^#baseurl=https://repo.almalinux.org|baseurl=https://mirrors.tencent.com|g",
)
// CentOS Stream
m.sedReplace("/etc/yum.repos.d/[Cc]ent*.repo",
"s|^mirrorlist=|#mirrorlist=|g",
"s|^#baseurl=http://mirror.centos.org/$contentdir|baseurl=https://mirrors.tencent.com/centos-stream|g",
)
return nil
}
func (m *dnfManager) EnableEPEL(ctx context.Context, inChina bool) error {
// 启用CRB
_, _ = m.executor.Run(ctx, "dnf", "config-manager", "--set-enabled", "crb")
_, _ = m.executor.Run(ctx, "/usr/bin/crb", "enable")
// 安装EPEL
result, _ := m.executor.Run(ctx, "dnf", "install", "-y", "epel-release")
if result == nil || result.ExitCode != 0 {
// 手动安装
var url string
if inChina {
url = "https://mirrors.tencent.com/epel/epel-release-latest-9.noarch.rpm"
} else {
url = "https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm"
}
_, _ = m.executor.Run(ctx, "dnf", "install", "-y", url)
}
_, _ = m.executor.Run(ctx, "dnf", "config-manager", "--set-enabled", "epel")
if inChina {
// 删除无镜像的repo
_ = os.Remove("/etc/yum.repos.d/epel-cisco-openh264.repo")
// 设置EPEL镜像
m.sedReplace("/etc/yum.repos.d/epel*.repo",
"s|^#baseurl=https://download.example/pub|baseurl=https://mirrors.tencent.com|g",
"s|^metalink|#metalink|g",
)
}
return nil
}
func (m *dnfManager) sedReplace(filePattern string, expressions ...string) {
for _, expr := range expressions {
_, _ = m.executor.Run(context.Background(), "sed", "-i", expr, filePattern)
}
}
// aptManager APT包管理器 (Debian/Ubuntu)
type aptManager struct {
executor Executor
osType types.OSType
}
func (m *aptManager) UpdateCache(ctx context.Context) error {
result, err := m.executor.Run(ctx, "apt-get", "update", "-y")
if err != nil {
return err
}
if result.ExitCode != 0 {
return fmt.Errorf("%s: %s", i18n.T.Get("apt-get update failed"), result.Stderr)
}
return nil
}
func (m *aptManager) Install(ctx context.Context, packages ...string) error {
args := append([]string{"install", "-y"}, packages...)
result, err := m.executor.Run(ctx, "apt-get", args...)
if err != nil {
return err
}
if result.ExitCode != 0 {
return fmt.Errorf("%s: %s", i18n.T.Get("apt-get install failed"), result.Stderr)
}
return nil
}
func (m *aptManager) Remove(ctx context.Context, packages ...string) error {
args := append([]string{"purge", "--auto-remove", "-y"}, packages...)
result, err := m.executor.Run(ctx, "apt-get", args...)
if err != nil {
return err
}
if result.ExitCode != 0 {
return fmt.Errorf("%s: %s", i18n.T.Get("apt-get remove failed"), result.Stderr)
}
return nil
}
func (m *aptManager) IsInstalled(ctx context.Context, pkg string) bool {
result, _ := m.executor.Run(ctx, "dpkg", "-s", pkg)
return result != nil && result.ExitCode == 0 && strings.Contains(result.Stdout, "Status: install ok installed")
}
func (m *aptManager) SetMirror(ctx context.Context, inChina bool) error {
if !inChina {
return nil
}
if m.osType == types.OSDebian {
// Debian
m.sedReplace("/etc/apt/sources.list", "s/deb.debian.org/mirrors.tencent.com/g")
m.sedReplace("/etc/apt/sources.list.d/debian.sources", "s/deb.debian.org/mirrors.tencent.com/g")
m.sedReplace("/etc/apt/sources.list",
"s|security.debian.org/\\? |security.debian.org/debian-security |g",
"s|security.debian.org|mirrors.tencent.com|g",
)
} else {
// Ubuntu
m.sedReplace("/etc/apt/sources.list", "s@//.*archive.ubuntu.com@//mirrors.tencent.com@g")
m.sedReplace("/etc/apt/sources.list.d/ubuntu.sources", "s@//.*archive.ubuntu.com@//mirrors.tencent.com@g")
m.sedReplace("/etc/apt/sources.list", "s/security.ubuntu.com/mirrors.tencent.com/g")
m.sedReplace("/etc/apt/sources.list.d/ubuntu.sources", "s/security.ubuntu.com/mirrors.tencent.com/g")
}
return nil
}
func (m *aptManager) EnableEPEL(ctx context.Context, inChina bool) error {
// APT不需要EPEL
return nil
}
func (m *aptManager) sedReplace(file string, expressions ...string) {
for _, expr := range expressions {
_, _ = m.executor.Run(context.Background(), "sed", "-i", expr, file)
}
}