refactor(packagemanager,cli,tui): move packages in specific subfolders

This commit is contained in:
Patryk Hegenberg 2025-02-04 16:11:03 +01:00
parent 11b8541630
commit e49138fdd2
34 changed files with 18 additions and 18 deletions

81
pkg/packagemanager/apt.go Normal file
View file

@ -0,0 +1,81 @@
package packagemanager
import (
"fmt"
"log"
"strings"
"system_setup_tool/internal/shell"
)
type AptManager struct {
SudoPassword string
}
func (a *AptManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(a, packages)
if err != nil {
return err
}
return nil
}
func (a *AptManager) Name() string {
return "OS Home Manager"
}
func (a *AptManager) InstallManager() error {
return nil
}
func (a *AptManager) InstallPackage(pkg string) error {
cmd := "apt install -y"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
return command.Run()
}
func (a *AptManager) RemovePackage(pkg string) error {
cmd := "apt remove -y"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
return command.Run()
}
func (a *AptManager) SearchPackage(pkg string) []string {
cmd := "apt search -y"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
packages, err := command.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", a.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (a *AptManager) UpdatePackage(pkg string) error {
cmd := "apt update -y"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
return command.Run()
}
func (a *AptManager) UpdateAllPackages() error {
cmd := "apt update -y"
fullCmd := fmt.Sprintf("%s", cmd)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
return command.Run()
}
func (a *AptManager) Check(pkg string) error {
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("dpkg -l | grep %s", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,69 @@
package packagemanager
import (
"fmt"
"os"
"path/filepath"
"system_setup_tool/internal/shell"
)
type CargoManager struct{}
func (c *CargoManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(c, packages)
if err != nil {
return err
}
return nil
}
func (c *CargoManager) Name() string {
return "Cargo"
}
func (c *CargoManager) InstallManager() error {
if _, err := shell.ExecLookPath("brew"); err != nil {
installHomebrew()
}
if _, err := shell.ExecLookPath("cargo"); err == nil {
return nil
}
cmd := shell.ExecCommand("brew", "install", "rust")
return cmd.Run()
}
func (c *CargoManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("cargo", "install", pkg)
return cmd.Run()
}
func (c *CargoManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("cargo", "uninstall", pkg)
return cmd.Run()
}
func (c *CargoManager) SearchPackage(pkg string) []string {
return []string{}
}
func (c *CargoManager) UpdatePackage(pkg string) error {
return fmt.Errorf("update not supported")
}
func (c *CargoManager) UpdateAllPackages() error {
return fmt.Errorf("update not supported")
}
func (c *CargoManager) Check(pkg string) error {
home, err := os.UserHomeDir()
if err != nil {
return err
}
cmd := shell.ExecCommand("ls", filepath.Join(home, ".cargo", "bin", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,46 @@
// cargo_test.go
package packagemanager
import (
"os/exec"
"system_setup_tool/internal/shell"
"testing"
)
func TestCargoManager_Name(t *testing.T) {
cm := &CargoManager{}
if name := cm.Name(); name != "Cargo" {
t.Errorf("Expected name to be 'Cargo', got %s", name)
}
}
func TestCargoManager_InstallManager(t *testing.T) {
cm := &CargoManager{}
// Mock exec.LookPath
shell.ExecLookPath = func(file string) (string, error) {
if file == "cargo" {
return "/usr/bin/cargo", nil
}
return "", exec.ErrNotFound
}
defer func() { shell.ExecLookPath = exec.LookPath }()
if err := cm.InstallManager(); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}
func TestCargoManager_InstallPackage(t *testing.T) {
cm := &CargoManager{}
// Mock exec.Command
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
return exec.Command("echo", "mocked cargo install")
}
defer func() { shell.ExecCommand = exec.Command }()
if err := cm.InstallPackage("test-package"); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}

View file

@ -0,0 +1,71 @@
package packagemanager
import (
"log"
"strings"
"system_setup_tool/internal/shell"
)
type ChocoManager struct{}
func (c *ChocoManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(c, packages)
if err != nil {
return err
}
return nil
}
func (c *ChocoManager) Name() string {
return "Chocolatey"
}
func (c *ChocoManager) InstallManager() error {
if _, err := shell.ExecLookPath("choco"); err == nil {
return nil
}
return installHomebrew()
}
func installChoco() error {
return nil
}
func (c *ChocoManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("choco", "install", pkg)
return cmd.Run()
}
func (c *ChocoManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("choco", "uninstall", pkg)
return cmd.Run()
}
func (c *ChocoManager) SearchPackage(pkg string) []string {
cmd := shell.ExecCommand("choco", "search", pkg)
packages, err := cmd.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", c.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (c *ChocoManager) UpdatePackage(pkg string) error {
cmd := shell.ExecCommand("choco", "update", pkg)
return cmd.Run()
}
func (c *ChocoManager) UpdateAllPackages() error {
cmd := shell.ExecCommand("choco", "update")
return cmd.Run()
}
func (c *ChocoManager) Check(pkg string) error {
cmd := shell.ExecCommand("choco", "search", "--local-only", pkg)
return cmd.Run()
}

78
pkg/packagemanager/dnf.go Normal file
View file

@ -0,0 +1,78 @@
package packagemanager
import (
"fmt"
"log"
"strings"
"system_setup_tool/internal/shell"
)
type DnfManager struct {
SudoPassword string
}
func (d *DnfManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(d, packages)
if err != nil {
return err
}
return nil
}
func (d *DnfManager) Name() string {
return "OS Home Manager"
}
func (d *DnfManager) InstallManager() error {
return nil
}
func (d *DnfManager) InstallPackage(pkg string) error {
cmd := "dnf install -y --best"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
return command.Run()
}
func (d *DnfManager) RemovePackage(pkg string) error {
cmd := "dnf remove -y"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
return command.Run()
}
func (d *DnfManager) SearchPackage(pkg string) []string {
cmd := shell.ExecCommand("dnf", "search", pkg)
packages, err := cmd.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", d.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (d *DnfManager) UpdatePackage(pkg string) error {
cmd := "dnf update -y"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
return command.Run()
}
func (d *DnfManager) UpdateAllPackages() error {
cmd := "dnf update -y"
fullCmd := fmt.Sprintf("%s", cmd)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
return command.Run()
}
func (d *DnfManager) Check(pkg string) error {
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("dnf list installed | grep %s", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,133 @@
package packagemanager
import (
"fmt"
"log"
"strings"
"system_setup_tool/internal/shell"
)
type FlatpakManager struct {
OS *OS
SudoPassword string
Config FlatpakConfig
}
func NewFlatpakManager(sudoPassword string, config FlatpakConfig) *FlatpakManager {
os, err := GetLinuxDistribution()
if err != nil {
log.Fatalf("error geting os information: %v", err)
}
return &FlatpakManager{
OS: os,
SudoPassword: sudoPassword,
Config: config,
}
}
func (f *FlatpakManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(f, packages)
if err != nil {
return err
}
return nil
}
func (f *FlatpakManager) Name() string {
return "Flatpak"
}
func (f *FlatpakManager) InstallManager() error {
if _, err := shell.ExecLookPath("flatpak"); err == nil {
return nil
}
err := installFlatpak(f.OS, f.SudoPassword)
if err != nil {
return err
}
err = addFlatpakRemotes(f.Config.Remotes)
if err != nil {
return err
}
return nil
}
type FlatpakConfig struct {
Enable bool `mapstructure:"enable"`
Remotes []Remote `mapstructure:"remotes"`
Packages []string `mapstructure:"packages"`
}
type Remote struct {
Name string `mapstructure:"name"`
URL string `mapstructure:"url"`
}
func installFlatpak(os *OS, sudoPassword string) error {
var command string
switch os.PackageManager {
case "pacman":
command = "pacman -S --noconfirm --needed flatpak"
case "apt":
command = "apt install -y flatpak"
case "dnf":
command = "dnf install -y flatpak"
default:
return fmt.Errorf("keine Flatpak-Installation für OS %s definiert", os.ID)
}
if err := InstallPackage(command, "", sudoPassword); err != nil {
return fmt.Errorf("fehler bei der Flatpak-Installation: %v", err)
}
return nil
}
func addFlatpakRemotes(remotes []Remote) error {
for _, remote := range remotes {
cmd := shell.ExecCommand("flatpak", "remote-add", "--if-not-exists", remote.Name, remote.URL)
if err := cmd.Run(); err != nil {
return fmt.Errorf("fehler beim Hinzufügen des Remotes %s: %v", remote.Name, err)
}
}
return nil
}
func (f *FlatpakManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("flatpak", "install", "-y", pkg)
return cmd.Run()
}
func (f *FlatpakManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("flatpak", "uninstall", "-y", pkg)
return cmd.Run()
}
func (f *FlatpakManager) SearchPackage(pkg string) []string {
cmd := shell.ExecCommand("flatpak", "search", pkg)
packages, err := cmd.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", f.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (f *FlatpakManager) UpdatePackage(pkg string) error {
cmd := shell.ExecCommand("flatpak", "update", "-y", pkg)
return cmd.Run()
}
func (f *FlatpakManager) UpdateAllPackages() error {
cmd := shell.ExecCommand("flatpak", "update", "-y")
return cmd.Run()
}
func (f *FlatpakManager) Check(pkg string) error {
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("flatpak list | grep %s", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,44 @@
package packagemanager
import (
"os/exec"
"system_setup_tool/internal/shell"
"testing"
)
func TestFlatpakManager_Name(t *testing.T) {
fm := &FlatpakManager{}
if name := fm.Name(); name != "Flatpak" {
t.Errorf("Expected name to be 'Flatpak', got %s", name)
}
}
func TestFlatpakManager_InstallManager(t *testing.T) {
fm := &FlatpakManager{
OS: &OS{PackageManager: "apt"},
SudoPassword: "testpass",
Config: FlatpakConfig{
Remotes: []Remote{{Name: "test", URL: "http://test.com"}},
},
}
// Mock exec.LookPath and other functions as needed
if err := fm.InstallManager(); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}
func TestFlatpakManager_InstallPackage(t *testing.T) {
fm := &FlatpakManager{}
// Mock exec.Command
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
return exec.Command("echo", "mocked flatpak install")
}
defer func() { shell.ExecCommand = exec.Command }()
if err := fm.InstallPackage("test-package"); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}

View file

@ -0,0 +1,69 @@
package packagemanager
import (
"fmt"
"os"
"path/filepath"
"system_setup_tool/internal/shell"
)
type GolangManager struct{}
func (g *GolangManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(g, packages)
if err != nil {
return err
}
return nil
}
func (g *GolangManager) Name() string {
return "Golang"
}
func (g *GolangManager) InstallManager() error {
if _, err := shell.ExecLookPath("brew"); err != nil {
installHomebrew()
}
if _, err := shell.ExecLookPath("go"); err == nil {
return nil
}
cmd := shell.ExecCommand("brew", "install", "golang")
return cmd.Run()
}
func (g *GolangManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("go", "install", pkg+"@latest")
return cmd.Run()
}
func (g *GolangManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("go", "uninstall", pkg)
return cmd.Run()
}
func (g *GolangManager) SearchPackage(pkg string) []string {
return []string{}
}
func (g *GolangManager) UpdatePackage(pkg string) error {
return fmt.Errorf("update not supported")
}
func (g *GolangManager) UpdateAllPackages() error {
return fmt.Errorf("update not supported")
}
func (g *GolangManager) Check(pkg string) error {
home, err := os.UserHomeDir()
if err != nil {
fmt.Printf("error: %v\n", err)
}
cmd := shell.ExecCommand("ls", filepath.Join(home, "go", "bin", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,45 @@
package packagemanager
import (
"os/exec"
"system_setup_tool/internal/shell"
"testing"
)
func TestGolangManager_Name(t *testing.T) {
gm := &GolangManager{}
if name := gm.Name(); name != "Golang" {
t.Errorf("Expected name to be 'Golang', got %s", name)
}
}
func TestGolangManager_InstallManager(t *testing.T) {
gm := &GolangManager{}
// Mock exec.LookPath
shell.ExecLookPath = func(file string) (string, error) {
if file == "go" {
return "/usr/local/go/bin/go", nil
}
return "", exec.ErrNotFound
}
defer func() { shell.ExecLookPath = exec.LookPath }()
if err := gm.InstallManager(); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}
func TestGolangManager_InstallPackage(t *testing.T) {
gm := &GolangManager{}
// Mock exec.Command
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
return exec.Command("echo", "mocked go install")
}
defer func() { shell.ExecCommand = exec.Command }()
if err := gm.InstallPackage("github.com/test/package"); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}

View file

@ -0,0 +1,76 @@
package packagemanager
import (
"fmt"
"log"
"strings"
"system_setup_tool/internal/shell"
)
type HomebrewManager struct{}
func (h *HomebrewManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(h, packages)
if err != nil {
return err
}
return nil
}
func (h *HomebrewManager) Name() string {
return "Homebrew"
}
func (h *HomebrewManager) InstallManager() error {
if _, err := shell.ExecLookPath("brew"); err == nil {
return nil
}
return installHomebrew()
}
func installHomebrew() error {
err := shell.ExecuteShellCommand("sh -c $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)", "NONINTERACTE=1")
if err != nil {
return fmt.Errorf("fehler bei der Installation von Homebrew: %v", err)
}
return nil
}
func (h *HomebrewManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("brew", "install", pkg)
return cmd.Run()
}
func (h *HomebrewManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("brew", "uninstall", pkg)
return cmd.Run()
}
func (h *HomebrewManager) SearchPackage(pkg string) []string {
cmd := shell.ExecCommand("brew", "search", pkg)
packages, err := cmd.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", h.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (h *HomebrewManager) UpdatePackage(pkg string) error {
cmd := shell.ExecCommand("brew", "upgrade", pkg)
return cmd.Run()
}
func (h *HomebrewManager) UpdateAllPackages() error {
cmd := shell.ExecCommand("brew", "upgrade")
return cmd.Run()
}
func (h *HomebrewManager) Check(pkg string) error {
cmd := shell.ExecCommand("brew", "list", pkg)
return cmd.Run()
}

View file

@ -0,0 +1,45 @@
package packagemanager
import (
"os/exec"
"system_setup_tool/internal/shell"
"testing"
)
func TestHomebrewManager_Name(t *testing.T) {
hm := &HomebrewManager{}
if name := hm.Name(); name != "Homebrew" {
t.Errorf("Expected name to be 'Homebrew', got %s", name)
}
}
func TestHomebrewManager_InstallManager(t *testing.T) {
hm := &HomebrewManager{}
// Mock exec.LookPath and executeShellCommand
shell.ExecLookPath = func(file string) (string, error) {
if file == "brew" {
return "/usr/local/bin/brew", nil
}
return "", exec.ErrNotFound
}
defer func() { shell.ExecLookPath = exec.LookPath }()
if err := hm.InstallManager(); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}
func TestHomebrewManager_InstallPackage(t *testing.T) {
hm := &HomebrewManager{}
// Mock exec.Command
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
return exec.Command("echo", "mocked brew install")
}
defer func() { shell.ExecCommand = exec.Command }()
if err := hm.InstallPackage("test-package"); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}

268
pkg/packagemanager/os.go Normal file
View file

@ -0,0 +1,268 @@
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()
}
func (o *OSManager) Check(pkg string) error {
return o.pm.Check(pkg)
}
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)
}
}

View file

@ -0,0 +1,44 @@
package packagemanager
import (
"testing"
)
func TestNewOSManager(t *testing.T) {
sudoPassword := "testpassword"
manager := NewOSManager(sudoPassword)
if manager.OS == nil {
t.Error("Expected OS to be non-nil")
}
if manager.SudoPassword != sudoPassword {
t.Errorf("Expected SudoPassword to be %s, got %s", sudoPassword, manager.SudoPassword)
}
}
func TestOSManagerName(t *testing.T) {
manager := &OSManager{}
if manager.Name() != "OS Package Manager" {
t.Errorf("Expected name to be 'OS Package Manager', got %s", manager.Name())
}
}
func TestParseOsRelease(t *testing.T) {
osReleaseContent := `
ID=ubuntu
NAME="Ubuntu"
VERSION_ID="20.04"
`
os := parseOsRelease(osReleaseContent)
if os.ID != "ubuntu" {
t.Errorf("Expected ID to be 'ubuntu', got %s", os.ID)
}
if os.Name != "Ubuntu" {
t.Errorf("Expected Name to be 'Ubuntu', got %s", os.Name)
}
if os.Version != "20.04" {
t.Errorf("Expected Version to be '20.04', got %s", os.Version)
}
}

View file

@ -0,0 +1,28 @@
package packagemanager
import (
"fmt"
"log"
"strings"
"system_setup_tool/internal/shell"
)
type Packages struct {
Headless []string `mapstructure:"headless"`
NonHeadless []string `mapstructure:"non_headless"`
}
func InstallPackage(cmd, pkg, sudoPassword string) error {
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(sudoPassword + "\n")
output, err := command.CombinedOutput()
if err != nil {
if strings.Contains(string(output), "not found") || strings.Contains(string(output), "no matching package") || strings.Contains(string(output), "Keine Übereinstimmung") || strings.Contains(string(output), "Ziel nicht gefunden") {
log.Printf("Package %s not available\n", pkg)
return nil
}
return fmt.Errorf("failed to install %s: %v\n%s", pkg, err, string(output))
}
return nil
}

View file

@ -0,0 +1,13 @@
package packagemanager
type PackageManager interface {
Install(packages []string) error
Check(pkg string) error
InstallPackage(pkg string) error
InstallManager() error
RemovePackage(pkg string) error
SearchPackage(pkg string) []string
UpdatePackage(pkg string) error
UpdateAllPackages() error
Name() string
}

View file

@ -0,0 +1,81 @@
package packagemanager
import (
"fmt"
"log"
"strings"
"system_setup_tool/internal/shell"
)
type PacmanManager struct {
SudoPassword string
}
func (m *PacmanManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(m, packages)
if err != nil {
return err
}
return nil
}
func (m *PacmanManager) Name() string {
return "OS Home Manager"
}
func (m *PacmanManager) InstallManager() error {
return nil
}
func (m *PacmanManager) InstallPackage(pkg string) error {
cmd := "pacman -S --noconfirm --needed"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(m.SudoPassword + "\n")
return command.Run()
}
func (m *PacmanManager) RemovePackage(pkg string) error {
cmd := "pacman -R"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(m.SudoPassword + "\n")
return command.Run()
}
func (p *PacmanManager) SearchPackage(pkg string) []string {
cmd := "pacman -Ss"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(p.SudoPassword + "\n")
packages, err := command.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", p.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (p *PacmanManager) UpdatePackage(pkg string) error {
cmd := "pacman -S"
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(p.SudoPassword + "\n")
return command.Run()
}
func (p *PacmanManager) UpdateAllPackages() error {
cmd := "apt -S"
fullCmd := fmt.Sprintf("%s", cmd)
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
command.Stdin = strings.NewReader(p.SudoPassword + "\n")
return command.Run()
}
func (p *PacmanManager) Check(pkg string) error {
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("paxman -Q | grep %s", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,66 @@
package packagemanager
import (
"fmt"
"system_setup_tool/internal/shell"
)
type PipxManager struct{}
func (p *PipxManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(p, packages)
if err != nil {
return err
}
return nil
}
func (p *PipxManager) Name() string {
return "Pipx"
}
func (p *PipxManager) InstallManager() error {
if _, err := shell.ExecLookPath("brew"); err != nil {
installHomebrew()
}
if _, err := shell.ExecLookPath("pipx"); err == nil {
return nil
}
cmd := shell.ExecCommand("brew", "install", "pipx")
return cmd.Run()
}
func (p *PipxManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("pipx", "install", pkg)
return cmd.Run()
}
func (p *PipxManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("pipx", "uninstall", pkg)
return cmd.Run()
}
func (p *PipxManager) SearchPackage(pkg string) []string {
return []string{}
}
func (p *PipxManager) UpdatePackage(pkg string) error {
cmd := shell.ExecCommand("pipx", "upgrade", pkg)
return cmd.Run()
}
func (p *PipxManager) UpdateAllPackages() error {
cmd := shell.ExecCommand("pipx", "upgrade-all")
return cmd.Run()
}
func (p *PipxManager) Check(pkg string) error {
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("pipx list | grep %s", pkg))
return cmd.Run()
}

View file

@ -0,0 +1,45 @@
package packagemanager
import (
"os/exec"
"system_setup_tool/internal/shell"
"testing"
)
func TestPipxManager_Name(t *testing.T) {
pm := &PipxManager{}
if name := pm.Name(); name != "Pipx" {
t.Errorf("Expected name to be 'Pipx', got %s", name)
}
}
func TestPipxManager_InstallManager(t *testing.T) {
pm := &PipxManager{}
// Mock exec.LookPath
shell.ExecLookPath = func(file string) (string, error) {
if file == "pipx" {
return "/usr/bin/pipx", nil
}
return "", exec.ErrNotFound
}
defer func() { shell.ExecLookPath = exec.LookPath }()
if err := pm.InstallManager(); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}
func TestPipxManager_InstallPackage(t *testing.T) {
pm := &PipxManager{}
// Mock exec.Command
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
return exec.Command("echo", "mocked pipx install")
}
defer func() { shell.ExecCommand = exec.Command }()
if err := pm.InstallPackage("test-package"); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}

View file

@ -0,0 +1,19 @@
package packagemanager
import (
"log"
"github.com/schollz/progressbar/v3"
)
func InstallWithProgress(manager PackageManager, packages []string) error {
bar := progressbar.Default(int64(len(packages)), "Installiere "+manager.Name()+"-Pakete...")
for _, pkg := range packages {
err := manager.InstallPackage(pkg)
if err != nil {
log.Printf("\nError installing %s: %v\n", pkg, err)
}
bar.Add(1)
}
return nil
}

30
pkg/packagemanager/win.go Normal file
View file

@ -0,0 +1,30 @@
//go:build windows
// +build windows
package packagemanager
import (
"fmt"
"golang.org/x/sys/windows/registry"
)
func platformInfoWin() (*OS, error) {
var result OS
result.ID = "Unknown"
result.Name = "Windows"
result.Version = "Unknown"
key, _ := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
productName, _, _ := key.GetStringValue("ProductName")
currentBuild, _, _ := key.GetStringValue("CurrentBuildNumber")
displayVersion, _, _ := key.GetStringValue("DisplayVersion")
releaseId, _, _ := key.GetStringValue("ReleaseId")
result.Name = productName
result.Version = fmt.Sprintf("%s (Build: %s)", releaseId, currentBuild)
result.ID = displayVersion
return &result, key.Close()
}

View file

@ -0,0 +1,8 @@
//go:build linux || darwin
// +build linux darwin
package packagemanager
func platformInfoWin() (*OS, error) {
return nil, nil
}

View file

@ -0,0 +1,71 @@
package packagemanager
import (
"log"
"strings"
"system_setup_tool/internal/shell"
)
type WingetManager struct{}
func (w *WingetManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
err := InstallWithProgress(w, packages)
if err != nil {
return err
}
return nil
}
func (w *WingetManager) Name() string {
return "Winget"
}
func (w *WingetManager) InstallManager() error {
if _, err := shell.ExecLookPath("winget"); err == nil {
return nil
}
return installHomebrew()
}
func installWinget() error {
return nil
}
func (w *WingetManager) InstallPackage(pkg string) error {
cmd := shell.ExecCommand("winget", "install", pkg)
return cmd.Run()
}
func (w *WingetManager) RemovePackage(pkg string) error {
cmd := shell.ExecCommand("winget", "uninstall", pkg)
return cmd.Run()
}
func (w *WingetManager) SearchPackage(pkg string) []string {
cmd := shell.ExecCommand("winget", "search", pkg)
packages, err := cmd.Output()
if err != nil {
log.Printf("error fetching %s packages: %v", w.Name(), err)
}
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
return packageList
}
func (w *WingetManager) UpdatePackage(pkg string) error {
cmd := shell.ExecCommand("winget", "update", pkg)
return cmd.Run()
}
func (w *WingetManager) UpdateAllPackages() error {
cmd := shell.ExecCommand("winget", "update")
return cmd.Run()
}
func (w *WingetManager) Check(pkg string) error {
cmd := shell.ExecCommand("wiget", "show", pkg)
return cmd.Run()
}