feat: first initial commit

This commit is contained in:
Patryk Hegenberg 2024-12-26 08:33:16 +01:00
commit 52739207a6
4 changed files with 563 additions and 0 deletions

356
main.go Normal file
View file

@ -0,0 +1,356 @@
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"runtime"
"strings"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func getLinuxDistribution() (string, error) {
data, err := os.ReadFile("/etc/os-release")
if err != nil {
return "", err
}
lines := strings.Split(string(data), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "ID=") {
return strings.Trim(strings.TrimPrefix(line, "ID="), "\""), nil
}
}
return "", fmt.Errorf("Linux distribution not found")
}
func getPackageManager(os string) (string, error) {
switch os {
case "debian", "ubuntu":
return "apt", nil
case "arch":
return "pacman", nil
case "fedora":
return "dnf", nil
default:
return "", fmt.Errorf("no packagemanager found for os: %s", os)
}
}
func getInstallCommand(pm string) (string, error) {
switch pm {
case "apt":
return "apt install -y", nil
case "pacman":
return "pacman -S --noconfirm", nil
case "dnf":
return "dnf install -y", nil
default:
return "", fmt.Errorf("no install command found for package manager: %s", pm)
}
}
func installPackage(cmd, pkg string) error {
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := exec.Command("sudo", "sh", "-c", fullCmd)
output, err := command.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to install %s: %v\n%s", pkg, err, string(output))
}
return nil
}
func downloadGolang(golangVersion string) error {
var link string
if runtime.GOARCH == "arm64" {
link = "https://go.dev/dl/go" + golangVersion + ".linux-arm64.tar.gz"
} else {
link = "https://go.dev/dl/go" + golangVersion + ".linux-amd64.tar.gz"
}
resp, err := http.Get(link)
if err != nil {
return fmt.Errorf("Fehler beim Herunterladen von Go: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Unerwarteter HTTP-Status: %s", resp.Status)
}
outFile, err := os.Create("go" + golangVersion + ".linux-" + runtime.GOARCH + ".tar.gz")
if err != nil {
return fmt.Errorf("Fehler beim Erstellen der Ausgabedatei: %v", err)
}
defer outFile.Close()
_, err = io.Copy(outFile, resp.Body)
if err != nil {
return fmt.Errorf("Fehler beim Schreiben der Ausgabedatei: %v", err)
}
return nil
}
func installSpecialSoftware() error {
if _, err := exec.LookPath("go"); err == nil {
fmt.Println("Go ist bereits installiert.")
} else {
golangVersion := "1.23.4"
if err := downloadGolang(golangVersion); err != nil {
return fmt.Errorf("Fehler beim Herunterladen von Go: %v", err)
}
golangCommand := fmt.Sprintf("sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go%s.linux-%s.tar.gz", golangVersion, runtime.GOARCH)
if err := installPackage(golangCommand, ""); err != nil {
return err
}
}
if _, err := exec.LookPath("rustc"); err == nil {
fmt.Println("Rust ist bereits installiert.")
} else {
rustupCommand := "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -- -q -y"
if err := installPackage(rustupCommand, ""); err != nil {
return err
}
}
if _, err := exec.LookPath("pipx"); err == nil {
fmt.Println("Pipx ist bereits installiert.")
} else {
pipXCommand := "python3 -m pip install --user pipx && python3 -m pipx ensurepath"
if err := installPackage(pipXCommand, ""); err != nil {
return err
}
}
return nil
}
type model struct {
list list.Model
packages []string
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if msg.String() == "q" {
return m, tea.Quit
}
case tea.WindowSizeMsg:
h, v := lipgloss.NewStyle().Margin(1, 2).GetFrameSize()
m.list.SetSize(msg.Width-h, msg.Height-v)
}
var cmd tea.Cmd
m.list, cmd = m.list.Update(msg)
return m, cmd
}
func (m model) View() string {
return "\n" + m.list.View()
}
var rootCmd = &cobra.Command{
Use: "package-installer",
Short: "Installiert Pakete basierend auf TOML-Konfiguration",
Run: run,
}
type Packages struct {
Headless []string `mapstructure:"headless"`
NonHeadless []string `mapstructure:"non_headless"`
}
type SpecialPackages struct {
Go []string `mapstructure:"go"`
Cargo []string `mapstructure:"cargo"`
Pipx []string `mapstructure:"pipx"`
}
type Config struct {
Headless bool `mapstructure:"headless"`
Packages Packages `mapstructure:"packages"`
SpecialPackages SpecialPackages `mapstructure:"special_packages"`
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringP("config", "c", "", "Pfad zur Konfigurationsdatei")
viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
}
func initConfig() {
if cfgFile := viper.GetString("config"); cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("config")
viper.AddConfigPath(".")
}
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Fehler beim Lesen der Konfigurationsdatei:", err)
os.Exit(1)
}
}
func installSpecialPackages(sp SpecialPackages) error {
for _, pkg := range sp.Go {
cmd := exec.Command("go", "install", pkg+"@latest")
if err := cmd.Run(); err != nil {
return fmt.Errorf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
for _, pkg := range sp.Cargo {
cmd := exec.Command("cargo", "install", pkg)
if err := cmd.Run(); err != nil {
return fmt.Errorf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
for _, pkg := range sp.Pipx {
cmd := exec.Command("pipx", "install", pkg)
if err := cmd.Run(); err != nil {
return fmt.Errorf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
return nil
}
type item string
func (i item) FilterValue() string { return string(i) }
func run(cmd *cobra.Command, args []string) {
os, err := getLinuxDistribution()
if err != nil {
log.Fatal(err)
}
pm, err := getPackageManager(os)
if err != nil {
log.Fatal(err)
}
installCommand, err := getInstallCommand(pm)
if err != nil {
log.Fatal(err)
}
var cfg 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)
}
var packages []string
packages = append(packages, cfg.Packages.Headless...)
if !cfg.Headless {
packages = append(packages, cfg.Packages.NonHeadless...)
}
// packages := viper.GetStringSlice("packages")
items := make([]list.Item, len(packages))
for i, pkg := range packages {
items[i] = item(pkg)
}
m := model{
list: list.New(items, list.NewDefaultDelegate(), 0, 0),
packages: packages,
}
m.list.Title = "Zu installierende Pakete"
p := tea.NewProgram(m)
if _, err := p.Run(); err != nil {
log.Fatal(err)
}
var confirm bool
form = huh.NewForm(
huh.NewGroup(
huh.NewConfirm().
Title("Möchten Sie mit der Installation fortfahren?").
Value(&confirm),
),
).WithTheme(huh.ThemeCatppuccin())
err = form.Run()
if err != nil {
log.Fatal(err)
}
if !confirm {
fmt.Println("Installation abgebrochen.")
return
}
for _, pkg := range packages {
if err := installPackage(installCommand, pkg); err != nil {
log.Printf("Fehler beim Installieren von %s: %v", pkg, err)
} else {
fmt.Printf("Erfolgreich installiert: %s\n", pkg)
}
}
var installSpecial bool
form = huh.NewForm(
huh.NewGroup(
huh.NewConfirm().
Title("Möchten Sie die speziellen Pakete (Go, Rust, Pipx) installieren?").
Value(&installSpecial),
),
).WithTheme(huh.ThemeCatppuccin())
err = form.Run()
if err != nil {
log.Fatal(err)
}
if installSpecial {
if err := installSpecialSoftware(); err != nil {
log.Printf("Fehler beim Installieren der speziellen Software: %v", err)
} else {
fmt.Println("Spezielle Software erfolgreich installiert")
}
} else {
fmt.Println("Installation der speziellen Pakete übersprungen")
}
if err := installSpecialPackages(cfg.SpecialPackages); err != nil {
log.Printf("Fehler bei der Installation spezieller Pakete: %v", err)
}
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}