From 0504d8877586ab4ac18a3d149c12f8eaa6be0788 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Wed, 15 Jan 2025 11:54:00 +0100 Subject: [PATCH] refactor: add progressbar and implement package interface --- cargo.go | 58 ++++++++++++++------- changelog.md | 11 ++++ config.go | 19 +++---- config.toml | 89 ++++++++++++++++---------------- flatpak.go | 73 +++++++++++++++++++------- go.mod | 6 ++- go.sum | 8 +++ golang.go | 58 ++++++++++++++------- homebrew.go | 61 ++++++++++++++-------- model.go | 51 +++++++++++-------- osinfo.go | 41 +++++++++++++++ packagemanager.go | 8 +++ pipx.go | 57 ++++++++++++++------- specialSoftware.go | 124 --------------------------------------------- tui.go | 97 +++++++++++++++++------------------ utils.go | 14 +++++ 16 files changed, 431 insertions(+), 344 deletions(-) create mode 100644 packagemanager.go delete mode 100644 specialSoftware.go diff --git a/cargo.go b/cargo.go index 929c091..df978f8 100644 --- a/cargo.go +++ b/cargo.go @@ -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() +} diff --git a/changelog.md b/changelog.md index a35e1ff..167b496 100644 --- a/changelog.md +++ b/changelog.md @@ -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 diff --git a/config.go b/config.go index 1f6b07c..287a3fa 100644 --- a/config.go +++ b/config.go @@ -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"` } diff --git a/config.toml b/config.toml index ca773d2..de478c8 100644 --- a/config.toml +++ b/config.toml @@ -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] diff --git a/flatpak.go b/flatpak.go index 2d91a1c..3624dd8 100644 --- a/flatpak.go +++ b/flatpak.go @@ -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() } diff --git a/go.mod b/go.mod index 2afa679..26aab19 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 9525042..9ae1aea 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/golang.go b/golang.go index 5c00da7..39c97c8 100644 --- a/golang.go +++ b/golang.go @@ -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() +} diff --git a/homebrew.go b/homebrew.go index b688986..fc0f5e2 100644 --- a/homebrew.go +++ b/homebrew.go @@ -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() } diff --git a/model.go b/model.go index 39af5ad..0b14fca 100644 --- a/model.go +++ b/model.go @@ -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 } diff --git a/osinfo.go b/osinfo.go index 519b9af..079c938 100644 --- a/osinfo.go +++ b/osinfo.go @@ -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 diff --git a/packagemanager.go b/packagemanager.go new file mode 100644 index 0000000..388540c --- /dev/null +++ b/packagemanager.go @@ -0,0 +1,8 @@ +package main + +type PackageManager interface { + Install(packages []string) error + InstallPackage(pkg string) error + InstallManager() error + Name() string +} diff --git a/pipx.go b/pipx.go index 94f437d..59e64ee 100644 --- a/pipx.go +++ b/pipx.go @@ -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() +} diff --git a/specialSoftware.go b/specialSoftware.go deleted file mode 100644 index 270dfe0..0000000 --- a/specialSoftware.go +++ /dev/null @@ -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) - } -} diff --git a/tui.go b/tui.go index b06d792..459c954 100644 --- a/tui.go +++ b/tui.go @@ -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 { diff --git a/utils.go b/utils.go index 2054ce2..4c2f522 100644 --- a/utils.go +++ b/utils.go @@ -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 +}