in order to implement sst for windows and macos the structure of osmanager has been changed. Now osmanager has a new field pm, which contains the specific packagemanager for the os. Linux packagemanagers have been implemented as packagemanagers on their own.
232 lines
5.1 KiB
Go
232 lines
5.1 KiB
Go
package packagemanager
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"system_setup_tool/internal/shell"
|
|
)
|
|
|
|
type OSManager struct {
|
|
OS *OS
|
|
SudoPassword string
|
|
pm PackageManager
|
|
}
|
|
|
|
func NewOSManager(sudoPassword string) *OSManager {
|
|
switch runtime.GOOS {
|
|
case "linux":
|
|
os, err := GetLinuxDistribution()
|
|
if err != nil {
|
|
log.Fatalf("error getting os information: %v", err)
|
|
}
|
|
var pm PackageManager
|
|
switch os.ID {
|
|
case "debian", "ubuntu":
|
|
pm = &AptManager{SudoPassword: sudoPassword}
|
|
case "arch":
|
|
pm = &PacmanManager{SudoPassword: sudoPassword}
|
|
case "fedora":
|
|
pm = &DnfManager{SudoPassword: sudoPassword}
|
|
default:
|
|
log.Fatalf("Unsupported Linux distribution: %s", os.ID)
|
|
}
|
|
return &OSManager{
|
|
OS: os,
|
|
SudoPassword: sudoPassword,
|
|
pm: pm,
|
|
}
|
|
case "windows":
|
|
os, err := getPlatformInfo()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
if _, err := shell.ExecLookPath("winget"); err == nil {
|
|
return &OSManager{
|
|
OS: os,
|
|
SudoPassword: "",
|
|
pm: &WingetManager{},
|
|
}
|
|
} else if _, err := shell.ExecLookPath("choco"); err == nil {
|
|
return &OSManager{
|
|
OS: os,
|
|
SudoPassword: "",
|
|
pm: &ChocoManager{},
|
|
}
|
|
} else {
|
|
log.Println("Neither Winget nor Chocolatey found on Windows. Package management functionality will be limited.")
|
|
}
|
|
case "darwin":
|
|
os, err := platformInfoMac()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
_, err = shell.ExecLookPath("brew")
|
|
if err == nil {
|
|
return &OSManager{
|
|
OS: os,
|
|
SudoPassword: sudoPassword,
|
|
pm: &HomebrewManager{},
|
|
}
|
|
} else {
|
|
manager := &HomebrewManager{}
|
|
manager.InstallManager()
|
|
return &OSManager{
|
|
OS: os,
|
|
SudoPassword: sudoPassword,
|
|
pm: manager,
|
|
}
|
|
}
|
|
default:
|
|
log.Fatal("Operating system not supported")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *OSManager) Name() string {
|
|
return "OS Package Manager"
|
|
}
|
|
|
|
func (o *OSManager) InstallManager() error { return nil }
|
|
|
|
func (o *OSManager) Install(packages []string) error {
|
|
if len(packages) == 0 {
|
|
return nil
|
|
}
|
|
err := InstallWithProgress(o.pm, packages)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *OSManager) InstallPackage(pkg string) error {
|
|
return o.pm.InstallPackage(pkg) //(o.OS.InstallCommand, pkg, o.SudoPassword)
|
|
}
|
|
|
|
func (o *OSManager) InstallBuildEssentials() error {
|
|
return InstallBuildEssentials(o.OS, o.SudoPassword)
|
|
}
|
|
|
|
func (o *OSManager) RemovePackage(pkg string) error {
|
|
return o.pm.RemovePackage(pkg)
|
|
}
|
|
|
|
func (o *OSManager) SearchPackage(pkg string) []string {
|
|
return o.pm.SearchPackage(pkg)
|
|
}
|
|
|
|
func (o *OSManager) UpdatePackage(pkg string) error {
|
|
return o.pm.UpdatePackage(pkg)
|
|
}
|
|
|
|
func (o *OSManager) UpdateAllPackages() error {
|
|
return o.pm.UpdateAllPackages()
|
|
}
|
|
|
|
type OS struct {
|
|
ID string
|
|
Name string
|
|
Version string
|
|
PackageManager string
|
|
}
|
|
|
|
func parseOsRelease(osRelease string) *OS {
|
|
var result OS
|
|
result.ID = "Unknown"
|
|
result.Name = "Unknown"
|
|
result.Version = "Unknown"
|
|
|
|
lines := strings.Split(osRelease, "\n")
|
|
|
|
for _, line := range lines {
|
|
splitLine := strings.SplitN(line, "=", 2)
|
|
if len(splitLine) != 2 {
|
|
continue
|
|
}
|
|
switch splitLine[0] {
|
|
case "ID":
|
|
result.ID = strings.ToLower(strings.Trim(splitLine[1], "\""))
|
|
case "NAME":
|
|
result.Name = strings.Trim(splitLine[1], "\"")
|
|
case "VERSION_ID":
|
|
result.Version = strings.Trim(splitLine[1], "\"")
|
|
}
|
|
}
|
|
return &result
|
|
}
|
|
|
|
func GetLinuxDistribution() (*OS, error) {
|
|
_, err := os.Stat("/etc/os-release")
|
|
if os.IsNotExist(err) {
|
|
return nil, fmt.Errorf("unable to read system information")
|
|
}
|
|
|
|
osRelease, _ := os.ReadFile("/etc/os-release")
|
|
return parseOsRelease(string(osRelease)), nil
|
|
}
|
|
|
|
func InstallBuildEssentials(os *OS, sudoPassword string) error {
|
|
var command string
|
|
switch os.PackageManager {
|
|
case "pacman":
|
|
command = "pacman -S --noconfirm --needed base-devel"
|
|
case "apt":
|
|
command = "apt install -y build-essential"
|
|
case "dnf":
|
|
command = "dnf install -y @development-tools"
|
|
default:
|
|
return fmt.Errorf("keine Build Essentials für OS %s definiert", os.ID)
|
|
}
|
|
|
|
fmt.Printf("Installiere Build Essentials für %s...\n", os.Name)
|
|
if err := InstallPackage(command, "", sudoPassword); err != nil {
|
|
return fmt.Errorf("error installing Build Essentials: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getSysctlValue(key string) (string, error) {
|
|
stdout, err := shell.ExecCommand(".", "sysctl", key).Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
version := strings.TrimPrefix(string(stdout), key+": ")
|
|
return strings.TrimSpace(version), nil
|
|
}
|
|
|
|
func platformInfoMac() (*OS, error) {
|
|
var result OS
|
|
result.ID = "Unknown"
|
|
result.Name = "MacOS"
|
|
result.Version = "Unknown"
|
|
|
|
version, err := getSysctlValue("kern.osproductversion")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result.Version = version
|
|
ID, err := getSysctlValue("kern.osversion")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result.ID = ID
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
func getPlatformInfo() (*OS, error) {
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
return platformInfoWin()
|
|
case "darwin":
|
|
return platformInfoMac()
|
|
case "linux":
|
|
return GetLinuxDistribution()
|
|
default:
|
|
return nil, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
|
|
}
|
|
}
|