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 package main
import ( import (
"fmt" // "fmt"
"log" // "log"
"os/exec" "os/exec"
) )
type CargoConfig struct { type CargoManager struct{}
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installCargoPackages(packages []string) error { func (c *CargoManager) Install(packages []string) error {
if len(packages) == 0 { if len(packages) == 0 {
return nil return nil
} }
// fmt.Printf("\nInstalliere %s-Pakete...\n", c.Name())
fmt.Println("\nInstalliere Cargo-Pakete...") err := installWithProgress(c, packages)
for _, pkg := range packages { if err != nil {
err := installPackageWithProgress(pkg, func() error { return err
cmd := exec.Command("cargo", "install", pkg)
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, 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 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 ### 🚀 Features
- Update config.toml
### 🚜 Refactor
- Change package management for different software sources
## [0.1.0] - 2024-12-28
### 🚀 Features
- First initial commit - First initial commit
- *(cli)* Add progress bar to instalation - *(cli)* Add progress bar to instalation
- *(config,cli)* Add packages and fix os find - *(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)* Add checks for pacman
- *(cli,config)* Add flatpak and dotfiles support - *(cli,config)* Add flatpak and dotfiles support
- *(cli)* Add a box display - *(cli)* Add a box display
- Prepare initial release
### 🐛 Bug Fixes ### 🐛 Bug Fixes

View file

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

View file

@ -16,6 +16,7 @@ headless = [
"python3-pip", "python3-pip",
"latexmk", "latexmk",
"luarocks", "luarocks",
"typst-cli",
] ]
non_headless = [ non_headless = [
@ -46,45 +47,7 @@ non_headless = [
"zathura-pdf-mupdf", "zathura-pdf-mupdf",
] ]
[go] [package_managers.homebrew]
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]
enable = true enable = true
packages = [ packages = [
"fd", "fd",
@ -92,8 +55,8 @@ packages = [
"ripgrep", "ripgrep",
"neovim", "neovim",
"helix", "helix",
"golang", # "golang",
"rust", # "rust",
"node", "node",
"yazi", "yazi",
"zk", "zk",
@ -115,12 +78,50 @@ packages = [
"yq", "yq",
"timewarrior", "timewarrior",
"tmux", "tmux",
"pipx", # "pipx",
"fastfetch", "fastfetch",
"stow", "stow",
"distrobox", "distrobox",
"asciidoc", # "asciidoc",
"asciidoctor", # "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] [dotfiles]

View file

@ -2,10 +2,60 @@ package main
import ( import (
"fmt" "fmt"
"log" // "log"
"os/exec" "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 { type FlatpakConfig struct {
Enable bool `mapstructure:"enable"` Enable bool `mapstructure:"enable"`
Remotes []Remote `mapstructure:"remotes"` Remotes []Remote `mapstructure:"remotes"`
@ -46,22 +96,7 @@ func addFlatpakRemotes(remotes []Remote) error {
return nil return nil
} }
func installFlatpakPackages(packages []string) error { func (f *FlatpakManager) InstallPackage(pkg string) error {
if len(packages) == 0 { cmd := exec.Command("flatpak", "install", "-y", pkg)
return nil return cmd.Run()
}
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
} }

6
go.mod
View file

@ -32,6 +32,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.16 // 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/hashstructure/v2 v2.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // 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/rivo/uniseg v0.4.7 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.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/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cast v1.6.0 // indirect
@ -52,8 +54,8 @@ require (
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/sync v0.9.0 // indirect golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.0.0-20221017184919-83659145692c // indirect golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.18.0 // indirect golang.org/x/text v0.18.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // 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.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 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/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 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= 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= 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/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 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= 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 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= 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.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 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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-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-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 h1:dveknrit5futqEmXAvd2I1BbZIDhxRijsyWHM86NlcA=
golang.org/x/term v0.0.0-20221017184919-83659145692c/go.mod h1:VTIZ7TEbF0BS9Sv9lPTvGbtW8i4z6GGbJBCM37uMCzY= 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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

View file

@ -1,32 +1,54 @@
package main package main
import ( import (
"fmt" // "fmt"
"log" // "log"
"os/exec" "os/exec"
) )
type GoConfig struct { type GolangManager struct{}
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installGoPackages(packages []string) error { func (g *GolangManager) Install(packages []string) error {
if len(packages) == 0 { if len(packages) == 0 {
return nil return nil
} }
// fmt.Printf("\nInstalliere %s-Pakete...\n", g.Name())
fmt.Println("\nInstalliere Golang-Pakete...") err := installWithProgress(g, packages)
for _, pkg := range packages { if err != nil {
err := installPackageWithProgress(pkg, func() error { return err
cmd := exec.Command("go", "install", pkg+"@latest")
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, 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 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 ( import (
"fmt" "fmt"
"log" // "log"
"os/exec" "os/exec"
) )
type HomebrewConfig struct { type HomebrewManager struct{}
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"` 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 { func installHomebrew() error {
@ -19,22 +51,7 @@ func installHomebrew() error {
return nil return nil
} }
func installHomebrewPackages(packages []string) error { func (h *HomebrewManager) InstallPackage(pkg string) error {
if len(packages) == 0 { cmd := exec.Command("brew", "install", pkg)
return nil return cmd.Run()
}
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

@ -3,8 +3,9 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"os/exec" "os/exec"
"runtime" "path/filepath"
"strings" "strings"
"github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/progress"
@ -34,28 +35,38 @@ func (m model) installSpecialSoftware() error {
return err return err
} }
} }
if _, err := exec.LookPath("go"); err == nil { homeDir, err := os.UserHomeDir()
fmt.Println("Go ist bereits installiert.") if err != nil {
} else { return fmt.Errorf("Fehler beim Ermitteln des Home-Verzeichnisses: %v", err)
golangVersion := "1.23.4" }
if err := downloadGolang(golangVersion); err != nil {
return fmt.Errorf("fehler beim Herunterladen von Go: %v", err) ohMyZshDir := filepath.Join(homeDir, ".oh-my-zsh")
} if _, err := os.Stat(ohMyZshDir); !os.IsNotExist(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) fmt.Println("Oh My Zsh ist bereits installiert.")
if err := installPackage(golangCommand, "", m.sudoPassword); err != nil { return nil
return err }
}
} fmt.Println("Installiere Oh My Zsh...")
err = executeShellCommand(`sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"`, "")
if _, err := exec.LookPath("rustc"); err == nil { if err != nil {
fmt.Println("Rust ist bereits installiert.") log.Printf("Fehler bei der Installation von Oh My Zsh: %v\n", err)
} else { }
rustupCommand := "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -q -y"
if err := installPackage(rustupCommand, "", ""); err != nil { plugins := []string{
return err "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 return nil
} }

View file

@ -6,8 +6,49 @@ import (
"os" "os"
"os/exec" "os/exec"
"strings" "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 { type OS struct {
ID string ID string
Name 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 package main
import ( import (
"fmt" // "fmt"
"log" // "log"
"os/exec" "os/exec"
) )
type PipxConfig struct { type PipxManager struct{}
Enable bool `mapstructure:"enable"`
Packages []string `mapstructure:"packages"`
}
func installPipxPackages(packages []string) error { func (p *PipxManager) Install(packages []string) error {
if len(packages) == 0 { if len(packages) == 0 {
return nil return nil
} }
fmt.Println("\nInstalliere Pipx-Pakete...") // fmt.Printf("\nInstalliere %s-Pakete...\n", p.Name())
for _, pkg := range packages { err := installWithProgress(p, packages)
err := installPackageWithProgress(pkg, func() error { if err != nil {
cmd := exec.Command("pipx", "install", pkg) return err
return cmd.Run()
})
if err != nil {
log.Printf("Fehler bei der Installation von %s: %v", pkg, 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 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" "fmt"
"log" "log"
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"
"github.com/mitchellh/mapstructure"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -50,31 +51,20 @@ func run(cmd *cobra.Command, args []string) {
log.Fatalf("Fehler bei der Benutzerabfrage: %v", err) 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{} unavailablePackages = []string{}
osManager := NewOSManager(os, sudoPassword, cfg.Packages.Headless)
m := newModel(packages, sudoPassword, os) if err := osManager.Install(cfg.Packages.Headless); err != nil {
p := tea.NewProgram(m) log.Printf("Warnung bei der Installation der Headless-Pakete: %v", err)
if _, err := p.Run(); err != nil { }
log.Fatal(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() 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 var installBuild bool
form = huh.NewForm( form = huh.NewForm(
huh.NewGroup( huh.NewGroup(
@ -90,7 +80,7 @@ func run(cmd *cobra.Command, args []string) {
} }
if installBuild { if installBuild {
if err := installBuildEssentials(os, sudoPassword); err != nil { if err := osManager.InstallBuildEssentials(); err != nil {
log.Printf("Warnung: %v", err) log.Printf("Warnung: %v", err)
} }
} }
@ -109,40 +99,45 @@ func run(cmd *cobra.Command, args []string) {
log.Fatal(err) log.Fatal(err)
} }
if installShellExtensions { if installShellExtensions {
sm := newSpecialSoftwareModel(sudoPassword) if err := osManager.InstallSpecialSoftware(); err != nil {
p = tea.NewProgram(sm) log.Printf("Warnung bei der Installation spezieller Software: %v", err)
if _, err := p.Run(); err != nil {
log.Fatal(err)
} }
} }
if cfg.Go.Enable { for name, config := range cfg.PackageManagers {
if err := installGoPackages(cfg.Go.Packages); err != nil { if config.Enable {
log.Printf("Warnung bei Homebrew-Paketen: %v", err) var manager PackageManager
} switch name {
} case "homebrew":
if cfg.Cargo.Enable { manager = &HomebrewManager{}
if err := installCargoPackages(cfg.Cargo.Packages); err != nil { case "go":
log.Printf("Warnung bei Homebrew-Paketen: %v", err) manager = &GolangManager{}
} case "cargo":
} manager = &CargoManager{}
if cfg.Pipx.Enable { case "pipx":
if err := installPipxPackages(cfg.Pipx.Packages); err != nil { manager = &PipxManager{}
log.Printf("Warnung bei Homebrew-Paketen: %v", err) case "flatpak":
} flatpakConfig := FlatpakConfig{}
} if err := mapstructure.Decode(config, &flatpakConfig); err != nil {
if cfg.Flatpak.Enable { log.Printf("Fehler beim Dekodieren der Flatpak-Konfiguration: %v", err)
fmt.Println("\nKonfiguriere Flatpak...") continue
if err := installFlatpak(os, sudoPassword); err != nil { }
log.Printf("Warnung bei Flatpak-Installation: %v", err) 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 { if err := manager.Install(config.Packages); err != nil {
log.Printf("Warnung bei Flatpak-Remotes: %v", err) log.Printf("Warnung bei %s-Paketen: %v", manager.Name(), err)
} }
if err := installFlatpakPackages(cfg.Flatpak.Packages); err != nil {
log.Printf("Warnung bei Flatpak-Paketen: %v", err)
} }
} }
if cfg.Dotfiles.Enable { if cfg.Dotfiles.Enable {

View file

@ -9,6 +9,7 @@ import (
"runtime" "runtime"
"github.com/charmbracelet/huh" "github.com/charmbracelet/huh"
"github.com/schollz/progressbar/v3"
) )
func getSudoPassword() (string, error) { func getSudoPassword() (string, error) {
@ -87,3 +88,16 @@ func executeShellCommand(command string, env string) error {
} }
return nil 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
}