feat: first initial commit
This commit is contained in:
commit
52739207a6
4 changed files with 563 additions and 0 deletions
356
main.go
Normal file
356
main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue