refactor(packagemanager,cli,tui): move packages in specific subfolders
This commit is contained in:
parent
11b8541630
commit
e49138fdd2
34 changed files with 18 additions and 18 deletions
18
internal/config/config.go
Normal file
18
internal/config/config.go
Normal 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"`
|
||||
}
|
||||
43
internal/dotfiles/dotfiles.go
Normal file
43
internal/dotfiles/dotfiles.go
Normal 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
115
internal/tui/tui.go
Normal 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
80
internal/utils/utils.go
Normal 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)
|
||||
}
|
||||
40
internal/utils/utils_test.go
Normal file
40
internal/utils/utils_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue