refactor: add progressbar and implement package interface

This commit is contained in:
Patryk Hegenberg 2025-01-15 11:54:00 +01:00
parent 8dabf244bb
commit 0504d88775
16 changed files with 431 additions and 344 deletions

View file

@ -1,32 +1,54 @@
package main
import (
"fmt"
"log"
// "fmt"
// "log"
"os/exec"
)
type CargoConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
type CargoManager struct{}
func installCargoPackages(packages []string) error {
func (c *CargoManager) Install(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.Printf("\nInstalliere %s-Pakete...\n", c.Name())
err := installWithProgress(c, packages)
if err != nil {
return err
}
// 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")
// fmt.Println("Installation abgeschlossen")
return nil
}
func (c *CargoManager) Name() string {
return "Cargo"
}
func (c *CargoManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err != nil {
installHomebrew()
}
if _, err := exec.LookPath("cargo"); err == nil {
return nil
}
cmd := exec.Command("brew", "install", "rust")
return cmd.Run()
}
func (c *CargoManager) InstallPackage(pkg string) error {
cmd := exec.Command("cargo", "install", pkg)
return cmd.Run()
}

View file

@ -6,6 +6,16 @@ All notable changes to this project will be documented in this file.
### 🚀 Features
- Update config.toml
### 🚜 Refactor
- Change package management for different software sources
## [0.1.0] - 2024-12-28
### 🚀 Features
- First initial commit
- *(cli)* Add progress bar to instalation
- *(config,cli)* Add packages and fix os find
@ -13,6 +23,7 @@ All notable changes to this project will be documented in this file.
- *(cli)* Add checks for pacman
- *(cli,config)* Add flatpak and dotfiles support
- *(cli)* Add a box display
- Prepare initial release
### 🐛 Bug Fixes

View file

@ -1,12 +1,13 @@
package main
type Config struct {
Headless bool `mapstructure:"headless"`
Packages Packages `mapstructure:"packages"`
Flatpak FlatpakConfig `mapstructure:"flatpak"`
Homebrew HomebrewConfig `mapstructure:"homebrew"`
Cargo CargoConfig `mapstructure:"cargo"`
Go GoConfig `mapstructure:"go"`
Pipx PipxConfig `mapstructure:"pipx"`
Dotfiles DotfilesConfig `mapstructure:"dotfiles"`
type PackageManagerConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
type Config struct {
Headless bool `mapstructure:"headless"`
Packages Packages `mapstructure:"packages"`
PackageManagers map[string]PackageManagerConfig `mapstructure:"package_managers"`
Dotfiles DotfilesConfig `mapstructure:"dotfiles"`
}

View file

@ -16,6 +16,7 @@ headless = [
"python3-pip",
"latexmk",
"luarocks",
"typst-cli",
]
non_headless = [
@ -46,45 +47,7 @@ non_headless = [
"zathura-pdf-mupdf",
]
[go]
enable = true
packages = [
"github.com/stefanlogue/meteor",
"golang.org/x/tools/gopls",
"github.com/go-delve/delve/cmd/dlv",
"github.com/air-verse/air",
# "go.senan.xyz/cliphist",
]
[cargo]
enable = true
packages = ["typst-cli"]
[pipx]
enable = true
packages = ["euporie"]
[flatpak]
enable = true
remotes = [
{ name = "flathub", url = "https://flathub.org/repo/flathub.flatpakrepo" },
]
packages = [
"com.spotify.Client",
"us.zoom.Zoom",
"org.zotero.Zotero",
"com.google.AndroidStudio",
"io.freetubeapp.FreeTube",
"com.discordapp.Discord",
"com.nextcloud.desktopclient.nextcloud",
"com.github.tchx84.Flatseal",
"io.github.flattool.Warehouse",
"org.onlyoffice.desktopeditors",
# "com.google.Chrome",
# "org.mozilla.Thunderbird",
]
[homebrew]
[package_managers.homebrew]
enable = true
packages = [
"fd",
@ -92,8 +55,8 @@ packages = [
"ripgrep",
"neovim",
"helix",
"golang",
"rust",
# "golang",
# "rust",
"node",
"yazi",
"zk",
@ -115,12 +78,50 @@ packages = [
"yq",
"timewarrior",
"tmux",
"pipx",
# "pipx",
"fastfetch",
"stow",
"distrobox",
"asciidoc",
"asciidoctor",
# "asciidoc",
# "asciidoctor",
]
[package_managers.go]
enable = true
packages = [
"github.com/stefanlogue/meteor",
"golang.org/x/tools/gopls",
"github.com/go-delve/delve/cmd/dlv",
"github.com/air-verse/air",
# "go.senan.xyz/cliphist",
]
[package_managers.cargo]
enable = true
packages = ["typst-cli"]
[package_managers.pipx]
enable = true
packages = ["euporie"]
[package_managers.flatpak]
enable = true
remotes = [
{ name = "flathub", url = "https://flathub.org/repo/flathub.flatpakrepo" },
]
packages = [
"com.spotify.Client",
"us.zoom.Zoom",
"org.zotero.Zotero",
"com.google.AndroidStudio",
"io.freetubeapp.FreeTube",
"com.discordapp.Discord",
"com.nextcloud.desktopclient.nextcloud",
"com.github.tchx84.Flatseal",
"io.github.flattool.Warehouse",
"org.onlyoffice.desktopeditors",
# "com.google.Chrome",
# "org.mozilla.Thunderbird",
]
[dotfiles]

View file

@ -2,10 +2,60 @@ package main
import (
"fmt"
"log"
// "log"
"os/exec"
)
type FlatpakManager struct {
OS *OS
SudoPassword string
Config FlatpakConfig
}
func (f *FlatpakManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
// fmt.Printf("\nInstalliere %s-Pakete...\n", f.Name())
err := installWithProgress(f, packages)
if err != nil {
return err
}
// for _, pkg := range packages {
// err := installPackageWithProgress(pkg, func() error {
// cmd := exec.Command("flatpak", "install", "-y", pkg)
// return cmd.Run()
// })
// if err != nil {
// log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
// }
// }
// fmt.Println("Installation abgeschlossen")
return nil
}
func (f *FlatpakManager) Name() string {
return "Flatpak"
}
func (f *FlatpakManager) InstallManager() error {
if _, err := exec.LookPath("flatpak"); err == nil {
return nil
}
err := installFlatpak(f.OS, f.SudoPassword)
if err != nil {
return err
}
err = addFlatpakRemotes(f.Config.Remotes)
if err != nil {
return err
}
return nil
}
type FlatpakConfig struct {
Enable bool `mapstructure:"enable"`
Remotes []Remote `mapstructure:"remotes"`
@ -46,22 +96,7 @@ func addFlatpakRemotes(remotes []Remote) error {
return nil
}
func installFlatpakPackages(packages []string) error {
if len(packages) == 0 {
return nil
}
fmt.Println("\nInstalliere Flatpak-Pakete...")
for _, pkg := range packages {
err := installPackageWithProgress(pkg, func() error {
cmd := exec.Command("flatpak", "install", "-y", pkg)
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, err)
}
}
return nil
func (f *FlatpakManager) InstallPackage(pkg string) error {
cmd := exec.Command("flatpak", "install", "-y", pkg)
return cmd.Run()
}

6
go.mod
View file

@ -32,6 +32,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
@ -42,6 +43,7 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/schollz/progressbar/v3 v3.18.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
@ -52,8 +54,8 @@ require (
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/term v0.0.0-20221017184919-83659145692c // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.18.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

8
go.sum
View file

@ -68,6 +68,8 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@ -96,6 +98,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
@ -152,10 +156,14 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20221017184919-83659145692c h1:dveknrit5futqEmXAvd2I1BbZIDhxRijsyWHM86NlcA=
golang.org/x/term v0.0.0-20221017184919-83659145692c/go.mod h1:VTIZ7TEbF0BS9Sv9lPTvGbtW8i4z6GGbJBCM37uMCzY=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

View file

@ -1,32 +1,54 @@
package main
import (
"fmt"
"log"
// "fmt"
// "log"
"os/exec"
)
type GoConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
type GolangManager struct{}
func installGoPackages(packages []string) error {
func (g *GolangManager) Install(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.Printf("\nInstalliere %s-Pakete...\n", g.Name())
err := installWithProgress(g, packages)
if err != nil {
return err
}
// 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")
// fmt.Println("Installation abgeschlossen")
return nil
}
func (g *GolangManager) Name() string {
return "Golang"
}
func (g *GolangManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err != nil {
installHomebrew()
}
if _, err := exec.LookPath("go"); err == nil {
return nil
}
cmd := exec.Command("brew", "install", "golang")
return cmd.Run()
}
func (g *GolangManager) InstallPackage(pkg string) error {
cmd := exec.Command("go", "install", pkg+"@latest")
return cmd.Run()
}

View file

@ -2,13 +2,45 @@ package main
import (
"fmt"
"log"
// "log"
"os/exec"
)
type HomebrewConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
type HomebrewManager struct{}
func (h *HomebrewManager) Install(packages []string) error {
if len(packages) == 0 {
return nil
}
// fmt.Printf("\nInstalliere %s-Pakete...\n", h.Name())
err := installWithProgress(h, packages)
if err != nil {
return err
}
// 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
}
func (h *HomebrewManager) Name() string {
return "Homebrew"
}
func (h *HomebrewManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err == nil {
return nil
}
return installHomebrew()
}
func installHomebrew() error {
@ -19,22 +51,7 @@ func installHomebrew() error {
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
func (h *HomebrewManager) InstallPackage(pkg string) error {
cmd := exec.Command("brew", "install", pkg)
return cmd.Run()
}

View file

@ -3,8 +3,9 @@ package main
import (
"fmt"
"log"
"os"
"os/exec"
"runtime"
"path/filepath"
"strings"
"github.com/charmbracelet/bubbles/progress"
@ -34,28 +35,38 @@ func (m model) installSpecialSoftware() error {
return err
}
}
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, "", m.sudoPassword); 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 -s -- -q -y"
if err := installPackage(rustupCommand, "", ""); err != nil {
return err
homeDir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("Fehler beim Ermitteln des Home-Verzeichnisses: %v", err)
}
ohMyZshDir := filepath.Join(homeDir, ".oh-my-zsh")
if _, err := os.Stat(ohMyZshDir); !os.IsNotExist(err) {
fmt.Println("Oh My Zsh ist bereits installiert.")
return nil
}
fmt.Println("Installiere Oh My Zsh...")
err = executeShellCommand(`sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"`, "")
if err != nil {
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)
}
}
fmt.Println("Oh My Zsh wurde erfolgreich installiert.")
return nil
}

View file

@ -6,8 +6,49 @@ import (
"os"
"os/exec"
"strings"
tea "github.com/charmbracelet/bubbletea"
)
type OSManager struct {
OS *OS
SudoPassword string
Packages []string
Model model
}
func NewOSManager(os *OS, sudoPassword string, packages []string) *OSManager {
return &OSManager{
OS: os,
SudoPassword: sudoPassword,
Packages: packages,
Model: newModel(packages, sudoPassword, os),
}
}
func (o *OSManager) Name() string {
return "OS Package Manager"
}
func (o *OSManager) InstallManager() error { return nil }
func (o *OSManager) Install(packages []string) error {
o.Packages = packages
o.Model = newModel(packages, o.SudoPassword, o.OS)
p := tea.NewProgram(o.Model)
_, err := p.Run()
return err
}
func (o *OSManager) InstallBuildEssentials() error {
return installBuildEssentials(o.OS, o.SudoPassword)
}
func (o *OSManager) InstallSpecialSoftware() error {
return o.Model.installSpecialSoftware()
}
type OS struct {
ID string
Name string

8
packagemanager.go Normal file
View file

@ -0,0 +1,8 @@
package main
type PackageManager interface {
Install(packages []string) error
InstallPackage(pkg string) error
InstallManager() error
Name() string
}

57
pipx.go
View file

@ -1,32 +1,55 @@
package main
import (
"fmt"
"log"
// "fmt"
// "log"
"os/exec"
)
type PipxConfig struct {
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
type PipxManager struct{}
func installPipxPackages(packages []string) error {
func (p *PipxManager) Install(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.Printf("\nInstalliere %s-Pakete...\n", p.Name())
err := installWithProgress(p, packages)
if err != nil {
return err
}
// 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")
// fmt.Println("Installation abgeschlossen")
return nil
}
func (p *PipxManager) Name() string {
return "Pipx"
}
func (p *PipxManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err != nil {
installHomebrew()
}
if _, err := exec.LookPath("pipx"); err == nil {
return nil
}
cmd := exec.Command("brew", "install", "pipx")
return cmd.Run()
}
func (p *PipxManager) InstallPackage(pkg string) error {
cmd := exec.Command("pipx", "install", pkg)
return cmd.Run()
}

View file

@ -1,124 +0,0 @@
package main
import (
"fmt"
"log"
"os"
"os/exec"
"github.com/charmbracelet/bubbles/progress"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type specialSoftwareModel struct {
items []string
index int
spinner spinner.Model
progress progress.Model
done bool
sudoPassword string
}
func newSpecialSoftwareModel(sudoPassword string) specialSoftwareModel {
items := []string{"oh-my-posh", "oh-my-zsh"}
p := progress.New(
progress.WithDefaultGradient(),
progress.WithWidth(40),
progress.WithoutPercentage(),
)
s := spinner.New()
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("63"))
return specialSoftwareModel{
items: items,
spinner: s,
progress: p,
sudoPassword: sudoPassword,
}
}
func (m specialSoftwareModel) Init() tea.Cmd {
return tea.Batch(m.installItemCmd(m.items[m.index]), m.spinner.Tick)
}
func (m specialSoftwareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc", "q":
return m, tea.Quit
}
case installedItemMsg:
if m.index >= len(m.items)-1 {
m.done = true
return m, tea.Quit
}
m.index++
progressCmd := m.progress.SetPercent(float64(m.index) / float64(len(m.items)))
return m, tea.Batch(
progressCmd,
tea.Printf("%s %s", checkMark, m.items[m.index-1]),
m.installItemCmd(m.items[m.index]),
)
case spinner.TickMsg:
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}
return m, nil
}
func (m specialSoftwareModel) View() string {
if m.done {
return doneStyle.Render("Spezielle Software Installation abgeschlossen!\n")
}
spin := m.spinner.View() + " "
prog := m.progress.View()
info := fmt.Sprintf("Installiere %s", m.items[m.index])
return spin + info + " " + prog
}
func (m specialSoftwareModel) installItemCmd(item string) tea.Cmd {
return func() tea.Msg {
switch item {
case "oh-my-posh":
if _, err := exec.LookPath("oh-my-posh"); err == nil {
return installedItemMsg(item)
}
err := executeShellCommand("curl -s https://ohmyposh.dev/install.sh | bash -s", "")
if err != nil {
log.Printf("Fehler bei der Installation von oh-my-posh: %v\n", err)
}
case "oh-my-zsh":
if _, err := os.Stat(os.Getenv("HOME") + "/.oh-my-zsh"); !os.IsNotExist(err) {
return installedItemMsg(item)
}
err := executeShellCommand(`sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"`, "")
if err != nil {
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)
}
}

97
tui.go
View file

@ -4,9 +4,10 @@ import (
"fmt"
"log"
tea "github.com/charmbracelet/bubbletea"
// tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
"github.com/mitchellh/mapstructure"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -50,31 +51,20 @@ func run(cmd *cobra.Command, args []string) {
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...)
}
unavailablePackages = []string{}
osManager := NewOSManager(os, sudoPassword, cfg.Packages.Headless)
m := newModel(packages, sudoPassword, os)
p := tea.NewProgram(m)
if _, err := p.Run(); err != nil {
log.Fatal(err)
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)
}
}
printUnavailablePackages()
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(
huh.NewGroup(
@ -90,7 +80,7 @@ func run(cmd *cobra.Command, args []string) {
}
if installBuild {
if err := installBuildEssentials(os, sudoPassword); err != nil {
if err := osManager.InstallBuildEssentials(); err != nil {
log.Printf("Warnung: %v", err)
}
}
@ -109,40 +99,45 @@ func run(cmd *cobra.Command, args []string) {
log.Fatal(err)
}
if installShellExtensions {
sm := newSpecialSoftwareModel(sudoPassword)
p = tea.NewProgram(sm)
if _, err := p.Run(); err != nil {
log.Fatal(err)
if err := osManager.InstallSpecialSoftware(); err != nil {
log.Printf("Warnung bei der Installation spezieller Software: %v", err)
}
}
if cfg.Go.Enable {
if err := installGoPackages(cfg.Go.Packages); err != nil {
log.Printf("Warnung bei Homebrew-Paketen: %v", err)
}
}
if cfg.Cargo.Enable {
if err := installCargoPackages(cfg.Cargo.Packages); err != nil {
log.Printf("Warnung bei Homebrew-Paketen: %v", err)
}
}
if cfg.Pipx.Enable {
if err := installPipxPackages(cfg.Pipx.Packages); err != nil {
log.Printf("Warnung bei Homebrew-Paketen: %v", err)
}
}
if cfg.Flatpak.Enable {
fmt.Println("\nKonfiguriere Flatpak...")
if err := installFlatpak(os, sudoPassword); err != nil {
log.Printf("Warnung bei Flatpak-Installation: %v", err)
}
for name, config := range cfg.PackageManagers {
if config.Enable {
var manager PackageManager
switch name {
case "homebrew":
manager = &HomebrewManager{}
case "go":
manager = &GolangManager{}
case "cargo":
manager = &CargoManager{}
case "pipx":
manager = &PipxManager{}
case "flatpak":
flatpakConfig := FlatpakConfig{}
if err := mapstructure.Decode(config, &flatpakConfig); err != nil {
log.Printf("Fehler beim Dekodieren der Flatpak-Konfiguration: %v", err)
continue
}
manager = &FlatpakManager{
OS: os,
SudoPassword: sudoPassword,
Config: flatpakConfig,
}
default:
log.Printf("Unbekannter Paketmanager: %s", name)
continue
}
if err := manager.InstallManager(); err != nil {
log.Printf("Warnung Packagemanager %s nicht vorhanden und konnte nicht installiert werden: %v", manager.Name(), err)
}
if err := addFlatpakRemotes(cfg.Flatpak.Remotes); err != nil {
log.Printf("Warnung bei Flatpak-Remotes: %v", err)
}
if err := installFlatpakPackages(cfg.Flatpak.Packages); err != nil {
log.Printf("Warnung bei Flatpak-Paketen: %v", err)
if err := manager.Install(config.Packages); err != nil {
log.Printf("Warnung bei %s-Paketen: %v", manager.Name(), err)
}
}
}
if cfg.Dotfiles.Enable {

View file

@ -9,6 +9,7 @@ import (
"runtime"
"github.com/charmbracelet/huh"
"github.com/schollz/progressbar/v3"
)
func getSudoPassword() (string, error) {
@ -87,3 +88,16 @@ func executeShellCommand(command string, env string) error {
}
return nil
}
func installWithProgress(manager PackageManager, packages []string) error {
bar := progressbar.Default(int64(len(packages)), "Installiere "+manager.Name()+"-Pakete...")
for _, pkg := range packages {
// fmt.Printf("Installing %s...\n", pkg)
err := manager.InstallPackage(pkg)
if err != nil {
fmt.Printf("Error installing %s: %v\n", pkg, err)
}
bar.Add(1)
}
return nil
}