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

18
internal/config/config.go Normal file
View file

@ -0,0 +1,18 @@
package config
import (
"system_setup_tool/internal/dotfiles"
pm "system_setup_tool/pkg/packagemanager"
)
type PackageManagerConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
type Config struct {
Headless bool `mapstructure:"headless"`
Packages pm.Packages `mapstructure:"packages"`
PackageManagers map[string]PackageManagerConfig `mapstructure:"package_managers"`
Dotfiles dotfiles.DotfilesConfig `mapstructure:"dotfiles"`
}

View file

@ -0,0 +1,43 @@
package dotfiles
import (
"fmt"
"log"
"os"
"path/filepath"
"system_setup_tool/internal/shell"
)
type DotfilesConfig struct {
Enable bool `mapstructure:"enable"`
GitRepo string `mapstructure:"git_repo"`
}
func SetupDotfiles(config DotfilesConfig) error {
if _, err := shell.ExecLookPath("git"); err != nil {
return fmt.Errorf("git ist nicht installiert")
}
if _, err := shell.ExecLookPath("stow"); err != nil {
return fmt.Errorf("gnu stow not installed")
}
dotfilesDir := filepath.Join(os.Getenv("HOME"), "dotfiles")
cmd := shell.ExecCommand("git", "clone", config.GitRepo, dotfilesDir)
if err := cmd.Run(); err != nil {
return fmt.Errorf("error cloning dotfiles: %v", err)
}
if err := os.Chdir(dotfilesDir); err != nil {
return fmt.Errorf("error changing into dotfiles directory: %v", err)
}
cmd = shell.ExecCommand("stow", ".", "--override='*'")
if err := cmd.Run(); err != nil {
log.Printf("error creating links: %v", err)
}
fmt.Printf("all linked properly\n")
return nil
}

115
internal/tui/tui.go Normal file
View file

@ -0,0 +1,115 @@
package tui
import (
"fmt"
"log"
"system_setup_tool/internal/config"
"system_setup_tool/internal/dotfiles"
"system_setup_tool/internal/utils"
pm "system_setup_tool/pkg/packagemanager"
"github.com/charmbracelet/huh"
"github.com/mitchellh/mapstructure"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
type installedPkgMsg string
func Run(cmd *cobra.Command, args []string) {
sudoPassword, err := utils.GetSudoPassword()
if err != nil {
log.Fatal(err)
}
var cfg config.Config
if err := viper.Unmarshal(&cfg); err != nil {
log.Fatalf("Fehler beim Lesen der Konfiguration: %v", err)
}
// form := huh.NewForm(
// huh.NewGroup(
// huh.NewConfirm().
// Title("Möchten Sie eine headless Installation durchführen?").
// Value(&cfg.Headless),
// ),
// ).WithTheme(huh.ThemeCatppuccin())
//
// if err := form.Run(); err != nil {
// log.Fatalf("Fehler bei der Benutzerabfrage: %v", err)
// }
//
// osManager := pm.NewOSManager(sudoPassword)
//
// if err := osManager.Install(cfg.Packages.Headless); err != nil {
// log.Printf("Warnung bei der Installation der Headless-Pakete: %v", err)
// }
// if !cfg.Headless {
// if err := osManager.Install(cfg.Packages.NonHeadless); err != nil {
// log.Printf("Warnung bei der Installation der Non-Headless-Pakete: %v", err)
// }
// }
//
for name, config := range cfg.PackageManagers {
if config.Enable {
var manager pm.PackageManager
switch name {
case "os":
manager = pm.NewOSManager(sudoPassword)
case "homebrew":
manager = &pm.HomebrewManager{}
case "go":
manager = &pm.GolangManager{}
case "cargo":
manager = &pm.CargoManager{}
case "pipx":
manager = &pm.PipxManager{}
case "flatpak":
flatpakConfig := pm.FlatpakConfig{}
if err := mapstructure.Decode(config, &flatpakConfig); err != nil {
log.Printf("error decoding flatpak config: %v", err)
continue
}
manager = pm.NewFlatpakManager(sudoPassword, flatpakConfig)
default:
log.Printf("unknown packagemanager: %s", name)
continue
}
if err := manager.InstallManager(); err != nil {
log.Printf("warning packagemanager %s not installed and could not be installed: %v", manager.Name(), err)
}
if err := manager.Install(config.Packages); err != nil {
log.Printf("warning at %s-packages: %v", manager.Name(), err)
}
}
}
osManager := pm.NewOSManager(sudoPassword)
var installBuild bool
form := huh.NewForm(
huh.NewGroup(
huh.NewConfirm().
Title("Möchten Sie die Build Essentials installieren?").
Value(&installBuild),
),
).WithTheme(huh.ThemeCatppuccin())
err = form.Run()
if err != nil {
log.Fatal(err)
}
if installBuild {
if err := osManager.InstallBuildEssentials(); err != nil {
log.Printf("Warnung: %v", err)
}
}
if cfg.Dotfiles.Enable {
fmt.Println("\nconfiguring dotfiles...")
if err := dotfiles.SetupDotfiles(cfg.Dotfiles); err != nil {
log.Printf("Warnung bei Dotfiles-Setup: %v", err)
}
}
}

80
internal/utils/utils.go Normal file
View file

@ -0,0 +1,80 @@
package utils
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/charmbracelet/huh"
)
func GetSudoPassword() (string, error) {
var password string
form := huh.NewForm(
huh.NewGroup(
huh.NewInput().
Title("Enter your password").
EchoMode(huh.EchoModePassword).
Value(&password),
),
).WithTheme(huh.ThemeCatppuccin())
err := form.Run()
if err != nil {
return "", fmt.Errorf("error at password-dialog: %v", err)
}
return password, nil
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
const (
maxHistoryLines = 2000
historyFileName = "sst_history"
)
func LogToHistory(action, pkg, manager string) error {
dirname, err := os.UserConfigDir()
if err != nil {
return fmt.Errorf("cant obtain config dir: %v", err)
}
historyFile := filepath.Join(dirname, "sst", historyFileName)
lines, err := readHistoryLines(historyFile)
if err != nil {
return err
}
timestamp := time.Now().Format("2006-01-02 15:04:05")
logEntry := fmt.Sprintf("%s: action: [%s] - package: [%s] - packagemanager: [%s]", timestamp, action, pkg, manager)
lines = append(lines, logEntry)
if len(lines) > maxHistoryLines {
lines = lines[len(lines)-maxHistoryLines:]
}
return writeHistoryLines(historyFile, lines)
}
func readHistoryLines(filePath string) ([]string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
if os.IsNotExist(err) {
return []string{}, nil
}
return nil, err
}
return strings.Split(string(content), "\n"), nil
}
func writeHistoryLines(filePath string, lines []string) error {
content := strings.Join(lines, "\n")
return os.WriteFile(filePath, []byte(content), 0644)
}

View file

@ -0,0 +1,40 @@
package utils
import (
"os/exec"
"system_setup_tool/internal/shell"
"testing"
)
func TestMax(t *testing.T) {
tests := []struct {
a, b, want int
}{
{1, 2, 2},
{5, 3, 5},
{0, 0, 0},
{-1, -5, -1},
}
for _, tt := range tests {
got := max(tt.a, tt.b)
if got != tt.want {
t.Errorf("max(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
}
}
}
func TestExecuteShellCommand(t *testing.T) {
// Mock execCommand
oldExecCommand := shell.ExecCommand
defer func() { shell.ExecCommand = oldExecCommand }()
shell.ExecCommand = func(command string, args ...string) *exec.Cmd {
return exec.Command("echo", "mocked command")
}
err := shell.ExecuteShellCommand("test command", "TEST_ENV=value")
if err != nil {
t.Errorf("executeShellCommand() error = %v; want nil", err)
}
}