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], "\"") } } err := result.getPackageManager() if err != nil { log.Fatal(err) } 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) } } func (os *OS) getPackageManager() error { switch os.ID { case "debian", "ubuntu": os.PackageManager = "apt" return nil case "arch": os.PackageManager = "pacman" return nil case "fedora": os.PackageManager = "dnf" return nil default: pmcommands := []string{ "apt", "dnf", "pacman", } for _, pmname := range pmcommands { _, err := shell.ExecLookPath(pmname) if err == nil { os.PackageManager = pmname return nil } } return fmt.Errorf("no packagemanager found fos os: %s", os.Name) } }