refactor: change package management for different software sources

This commit is contained in:
Patryk Hegenberg 2025-01-12 23:38:14 +01:00
parent f14b54ea20
commit c4fbac6b8d
12 changed files with 289 additions and 170 deletions

32
cargo.go Normal file
View file

@ -0,0 +1,32 @@
package main
import (
"fmt"
"log"
"os/exec"
)
type CargoConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installCargoPackages(packages []string) error {
if len(packages) == 0 {
return nil
}
fmt.Println("\nInstalliere Cargo-Pakete...")
for _, pkg := range packages {
err := installPackageWithProgress(pkg, func() error {
cmd := exec.Command("cargo", "install", pkg)
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
fmt.Println("Installation abgeschlossen")
return nil
}

View file

@ -1,9 +1,12 @@
package main package main
type Config struct { type Config struct {
Headless bool `mapstructure:"headless"` Headless bool `mapstructure:"headless"`
Packages Packages `mapstructure:"packages"` Packages Packages `mapstructure:"packages"`
SpecialPackages SpecialPackages `mapstructure:"special_packages"` Flatpak FlatpakConfig `mapstructure:"flatpak"`
Flatpak FlatpakConfig `mapstructure:"flatpak"` Homebrew HomebrewConfig `mapstructure:"homebrew"`
Dotfiles DotfilesConfig `mapstructure:"dotfiles"` Cargo CargoConfig `mapstructure:"cargo"`
Go GoConfig `mapstructure:"go"`
Pipx PipxConfig `mapstructure:"pipx"`
Dotfiles DotfilesConfig `mapstructure:"dotfiles"`
} }

View file

@ -1,37 +1,19 @@
headless = false headless = true
[packages] [packages]
headless = [ headless = [
"git", "git",
"curl", "curl",
"wget", "wget",
"ripgrep",
"bottom",
"bat",
"biber", "biber",
"bear", "bear",
"docker", "docker",
"docker-compose", "docker-compose",
"fd",
"bat",
"lsd",
"zsh", "zsh",
"jq",
"neofetch",
"neovim",
"helix",
"npm", "npm",
"stow",
"task", "task",
"timew",
"typst-lsp",
"tree-sitter-cli", "tree-sitter-cli",
"tmux",
"zoxide",
"python3-pip", "python3-pip",
"pipx",
"golang",
"rustup",
"latexmk", "latexmk",
"luarocks", "luarocks",
] ]
@ -40,7 +22,6 @@ non_headless = [
"discord", "discord",
"flameshot", "flameshot",
"fuzzel", "fuzzel",
"google-chrome",
"hyprcursor", "hyprcursor",
"hypridle", "hypridle",
"hyprland", "hyprland",
@ -54,8 +35,6 @@ non_headless = [
"neovide", "neovide",
"pidgin", "pidgin",
"remmina", "remmina",
"spotify",
"thunderbird",
"thunderbird-i18n-de", "thunderbird-i18n-de",
"virt-manager", "virt-manager",
"vlc", "vlc",
@ -64,24 +43,26 @@ non_headless = [
"zathura", "zathura",
"zathura-pdf-mupdf", "zathura-pdf-mupdf",
"zoom", "zoom",
"zotero",
"android-studio", "android-studio",
] ]
[special_packages] [go]
go = [ enable = true
"github.com/jesseduffield/lazygit", packages = [
"github.com/stefanlogue/meteor", "github.com/stefanlogue/meteor",
"golang.org/x/tools/gopls", "golang.org/x/tools/gopls",
"github.com/go-delve/delve/cmd/dlv", "github.com/go-delve/delve/cmd/dlv",
"github.com/air-verse/air", "github.com/air-verse/air",
"go.senan.xyz/cliphist", # "go.senan.xyz/cliphist",
"github.com/goreleaser/goreleaser/v2",
] ]
cargo = ["git-cliff", "bottom", "typst-cli"] [cargo]
enable = true
packages = ["typst-cli"]
pipx = ["harlequin", "posting", "euporie"] [pipx]
enable = true
packages = ["euporie"]
[flatpak] [flatpak]
enable = true enable = true
@ -96,8 +77,52 @@ packages = [
"io.freetubeapp.FreeTube", "io.freetubeapp.FreeTube",
"com.discordapp.Discord", "com.discordapp.Discord",
"com.nextcloud.desktopclient.nextcloud", "com.nextcloud.desktopclient.nextcloud",
"com.github.tchx84.Flatseal",
"io.github.flattool.Warehouse",
"org.onlyoffice.desktopeditors",
# "com.google.Chrome",
# "org.mozilla.Thunderbird",
]
[homebrew]
enable = true
packages = [
"fd",
"fzf",
"ripgrep",
"neovim",
"helix",
"golang",
"rust",
"node",
"yazi",
"zk",
"bat",
"bottom",
"btop",
"git-cliff",
"glow",
"lazygit",
"goreleaser",
"harlequin",
"mage",
"posting",
"typst",
"wails",
"zoxide",
"lsd",
"jq",
"yq",
"timewarrior",
"tmux",
"pipx",
"fastfetch",
"stow",
"distrobox",
"asciidoc",
"asciidoctor",
] ]
[dotfiles] [dotfiles]
enable = true enable = false
git_repo = "https://codeberg.org/Pata1704/dotfiles.git" git_repo = "https://codeberg.org/Pata1704/dotfiles.git"

View file

@ -4,8 +4,6 @@ import (
"fmt" "fmt"
"log" "log"
"os/exec" "os/exec"
"github.com/charmbracelet/bubbles/progress"
) )
type FlatpakConfig struct { type FlatpakConfig struct {
@ -54,19 +52,15 @@ func installFlatpakPackages(packages []string) error {
} }
fmt.Println("\nInstalliere Flatpak-Pakete...") fmt.Println("\nInstalliere Flatpak-Pakete...")
p := progress.New(
progress.WithDefaultGradient(),
progress.WithWidth(40),
)
for i, pkg := range packages { for _, pkg := range packages {
p.SetPercent(float64(i) / float64(len(packages)))
fmt.Printf("Installiere Flatpak: %s\n", pkg)
cmd := exec.Command("flatpak", "install", "-y", pkg) err := installPackageWithProgress(pkg, func() error {
if err := cmd.Run(); err != nil { cmd := exec.Command("flatpak", "install", "-y", pkg)
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, err) log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
continue
} }
} }
return nil return nil

32
golang.go Normal file
View file

@ -0,0 +1,32 @@
package main
import (
"fmt"
"log"
"os/exec"
)
type GoConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installGoPackages(packages []string) error {
if len(packages) == 0 {
return nil
}
fmt.Println("\nInstalliere Golang-Pakete...")
for _, pkg := range packages {
err := installPackageWithProgress(pkg, func() error {
cmd := exec.Command("go", "install", pkg+"@latest")
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
fmt.Println("Installation abgeschlossen")
return nil
}

40
homebrew.go Normal file
View file

@ -0,0 +1,40 @@
package main
import (
"fmt"
"log"
"os/exec"
)
type HomebrewConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installHomebrew() error {
err := 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 installHomebrewPackages(packages []string) error {
if len(packages) == 0 {
return nil
}
fmt.Println("\nInstalliere Homebrew-Pakete...")
for _, pkg := range packages {
err := installPackageWithProgress(pkg, func() error {
cmd := exec.Command("brew", "install", pkg)
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
fmt.Println("Installation abgeschlossen")
return nil
}

View file

@ -56,15 +56,6 @@ func (m model) installSpecialSoftware() error {
} }
} }
// 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 return nil
} }

View file

@ -11,12 +11,6 @@ type Packages struct {
NonHeadless []string `mapstructure:"non_headless"` NonHeadless []string `mapstructure:"non_headless"`
} }
type SpecialPackages struct {
Go []string `mapstructure:"go"`
Cargo []string `mapstructure:"cargo"`
Pipx []string `mapstructure:"pipx"`
}
func installPackage(cmd, pkg, sudoPassword string) error { func installPackage(cmd, pkg, sudoPassword string) error {
fullCmd := fmt.Sprintf("%s %s", cmd, pkg) fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
command := exec.Command("sudo", "-S", "sh", "-c", fullCmd) command := exec.Command("sudo", "-S", "sh", "-c", fullCmd)
@ -32,31 +26,6 @@ func installPackage(cmd, pkg, sudoPassword string) error {
return nil return nil
} }
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
}
func printUnavailablePackages() { func printUnavailablePackages() {
if len(unavailablePackages) > 0 { if len(unavailablePackages) > 0 {
fmt.Println("\nFolgende Pakete waren nicht verfügbar:") fmt.Println("\nFolgende Pakete waren nicht verfügbar:")

32
pipx.go Normal file
View file

@ -0,0 +1,32 @@
package main
import (
"fmt"
"log"
"os/exec"
)
type PipxConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installPipxPackages(packages []string) error {
if len(packages) == 0 {
return nil
}
fmt.Println("\nInstalliere Pipx-Pakete...")
for _, pkg := range packages {
err := installPackageWithProgress(pkg, func() error {
cmd := exec.Command("pipx", "install", pkg)
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
fmt.Println("Installation abgeschlossen")
return nil
}

View file

@ -3,8 +3,8 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"os/exec" "os/exec"
"runtime"
"github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/progress"
"github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/spinner"
@ -22,7 +22,7 @@ type specialSoftwareModel struct {
} }
func newSpecialSoftwareModel(sudoPassword string) specialSoftwareModel { func newSpecialSoftwareModel(sudoPassword string) specialSoftwareModel {
items := []string{"oh-my-posh", "golang", "rust"} items := []string{"oh-my-posh", "oh-my-zsh"}
p := progress.New( p := progress.New(
progress.WithDefaultGradient(), progress.WithDefaultGradient(),
@ -92,42 +92,33 @@ func (m specialSoftwareModel) installItemCmd(item string) tea.Cmd {
if _, err := exec.LookPath("oh-my-posh"); err == nil { if _, err := exec.LookPath("oh-my-posh"); err == nil {
return installedItemMsg(item) return installedItemMsg(item)
} }
err := executeShellCommand("curl -s https://ohmyposh.dev/install.sh | bash -s") err := executeShellCommand("curl -s https://ohmyposh.dev/install.sh | bash -s", "")
if err != nil { if err != nil {
log.Printf("Fehler bei der Installation von oh-my-posh: %v\n", err) log.Printf("Fehler bei der Installation von oh-my-posh: %v\n", err)
} }
case "golang": case "oh-my-zsh":
if _, err := exec.LookPath("go"); err == nil { if _, err := os.Stat(os.Getenv("HOME") + "/.oh-my-zsh"); !os.IsNotExist(err) {
return installedItemMsg(item) return installedItemMsg(item)
} }
golangVersion := "1.23.4" err := executeShellCommand(`sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"`, "")
if err := downloadGolang(golangVersion); err != nil {
log.Printf("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, "", m.sudoPassword); err != nil {
log.Printf("Fehler beim Installieren von Go: %v", err)
}
case "rust":
if _, err := exec.LookPath("rustc"); err == nil {
if _, err := exec.LookPath("cargo"); err == nil {
return installedItemMsg(item)
}
}
err := executeShellCommand("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -q -y")
if err != nil { if err != nil {
log.Printf("Fehler bei der Installation von rustup: %v\n", err) log.Printf("Fehler bei der Installation von Oh My Zsh: %v\n", err)
}
plugins := []string{
"git clone https://github.com/zsh-users/zsh-autosuggestions.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions",
"git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting",
"git clone https://github.com/zdharma-continuum/fast-syntax-highlighting.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/fast-syntax-highlighting",
"git clone --depth 1 -- https://github.com/marlonrichert/zsh-autocomplete.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autocomplete",
}
for _, plugin := range plugins {
err := executeShellCommand(plugin, "")
if err != nil {
log.Printf("Fehler bei der Installation des Plugins: %v\n", err)
}
} }
} }
return installedItemMsg(item) return installedItemMsg(item)
} }
} }
func executeShellCommand(command string) error {
cmd := exec.Command("bash", "-c", command)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("befehl fehlgeschlagen: %v\nAusgabe: %s", err, output)
}
return nil
}

92
tui.go
View file

@ -3,9 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"os/exec"
"github.com/charmbracelet/bubbles/progress"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh" "github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
@ -68,12 +66,21 @@ func run(cmd *cobra.Command, args []string) {
printUnavailablePackages() printUnavailablePackages()
var installSpecial bool if cfg.Homebrew.Enable {
if err := installHomebrew(); err != nil {
log.Printf("Warnung: %v", err)
}
if err := installHomebrewPackages(cfg.Homebrew.Packages); err != nil {
log.Printf("Warnung bei Homebrew-Paketen: %v", err)
}
}
var installBuild bool
form = huh.NewForm( form = huh.NewForm(
huh.NewGroup( huh.NewGroup(
huh.NewConfirm(). huh.NewConfirm().
Title("Möchten Sie die speziellen Pakete (Go, Rust, Pipx) installieren?"). Title("Möchten Sie die Build Essentials installieren?").
Value(&installSpecial), Value(&installBuild),
), ),
).WithTheme(huh.ThemeCatppuccin()) ).WithTheme(huh.ThemeCatppuccin())
@ -82,10 +89,26 @@ func run(cmd *cobra.Command, args []string) {
log.Fatal(err) log.Fatal(err)
} }
if installSpecial { if installBuild {
if err := installBuildEssentials(os, sudoPassword); err != nil { if err := installBuildEssentials(os, sudoPassword); err != nil {
log.Printf("Warnung: %v", err) log.Printf("Warnung: %v", err)
} }
}
var installShellExtensions bool
form = huh.NewForm(
huh.NewGroup(
huh.NewConfirm().
Title("Möchten Sie die Shell-Extensions installieren?").
Value(&installShellExtensions),
),
).WithTheme(huh.ThemeCatppuccin())
err = form.Run()
if err != nil {
log.Fatal(err)
}
if installShellExtensions {
sm := newSpecialSoftwareModel(sudoPassword) sm := newSpecialSoftwareModel(sudoPassword)
p = tea.NewProgram(sm) p = tea.NewProgram(sm)
if _, err := p.Run(); err != nil { if _, err := p.Run(); err != nil {
@ -93,54 +116,19 @@ func run(cmd *cobra.Command, args []string) {
} }
} }
if len(cfg.SpecialPackages.Go) > 0 || len(cfg.SpecialPackages.Cargo) > 0 || len(cfg.SpecialPackages.Pipx) > 0 { if cfg.Go.Enable {
var allSpecialPkgs []struct { if err := installGoPackages(cfg.Go.Packages); err != nil {
typ string log.Printf("Warnung bei Homebrew-Paketen: %v", err)
name string
command string
} }
}
for _, pkg := range cfg.SpecialPackages.Go { if cfg.Cargo.Enable {
allSpecialPkgs = append(allSpecialPkgs, struct { if err := installCargoPackages(cfg.Cargo.Packages); err != nil {
typ string log.Printf("Warnung bei Homebrew-Paketen: %v", err)
name string
command string
}{"go", pkg, "go install " + pkg + "@latest"})
} }
}
for _, pkg := range cfg.SpecialPackages.Cargo { if cfg.Pipx.Enable {
allSpecialPkgs = append(allSpecialPkgs, struct { if err := installPipxPackages(cfg.Pipx.Packages); err != nil {
typ string log.Printf("Warnung bei Homebrew-Paketen: %v", err)
name string
command string
}{"cargo", pkg, "cargo install " + pkg})
}
for _, pkg := range cfg.SpecialPackages.Pipx {
allSpecialPkgs = append(allSpecialPkgs, struct {
typ string
name string
command string
}{"pipx", pkg, "pipx install " + pkg})
}
if len(allSpecialPkgs) > 0 {
fmt.Println("\nInstalliere spezielle Pakete...")
p := progress.New(
progress.WithDefaultGradient(),
progress.WithWidth(40),
)
for i, pkg := range allSpecialPkgs {
p.SetPercent(float64(i) / float64(len(allSpecialPkgs)))
fmt.Printf("Installiere %s Paket: %s\n", pkg.typ, pkg.name)
cmd := exec.Command("sh", "-c", pkg.command)
if err := cmd.Run(); err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg.name, err)
continue
}
}
} }
} }
if cfg.Flatpak.Enable { if cfg.Flatpak.Enable {

View file

@ -5,6 +5,7 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"os/exec"
"runtime" "runtime"
"github.com/charmbracelet/huh" "github.com/charmbracelet/huh"
@ -65,3 +66,24 @@ func max(a, b int) int {
} }
return b return b
} }
func installPackageWithProgress(name string, installFunc func() error) error {
err := installFunc()
if err != nil {
fmt.Printf("\r❌ %s\n", name)
return err
}
fmt.Printf("\r✓ %s\n", name)
return nil
}
func executeShellCommand(command string, env string) error {
cmd := exec.Command("bash", "-c", command)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, env)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("befehl fehlgeschlagen: %v\nAusgabe: %s", err, output)
}
return nil
}