Compare commits
46 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea317efaa4 | |||
| 5c00c164dd | |||
|
|
0a7a1c43d9 | ||
| e5ef2f0b88 | |||
| 9597007953 | |||
| 73881bf9b5 | |||
|
|
3cd2187932 | ||
| 956aad51f5 | |||
| 2081b002e5 | |||
|
|
fc2372e0b1 | ||
|
|
9c8b19405a | ||
| db4892c08a | |||
|
|
2f5c05bea2 | ||
| 594d7e48f5 | |||
| 5a92382063 | |||
| 179e2a6ec3 | |||
| 0cc50e15c9 | |||
| e49138fdd2 | |||
| 11b8541630 | |||
| 3519efeccc | |||
| b18b7761fc | |||
| 7d4a54b34c | |||
| 8ed3b0c013 | |||
| f8abf29594 | |||
| 70dbc9e062 | |||
| 53a50f2be4 | |||
| afaf7707aa | |||
| 0306ad36ef | |||
| 05e774764f | |||
| fc966df8f5 | |||
| 8281883e4d | |||
| 8dabc7357b | |||
| 43eb3ae4cb | |||
| f39051f93d | |||
| 3b1799397e | |||
| cc3cc5c916 | |||
| 7f9d72bddd | |||
| a90c3d52f9 | |||
| f76829cb92 | |||
| 5b7775f33e | |||
|
|
7f951585c8 | ||
| 24662bc91c | |||
| 4006852790 | |||
| c0be9a6b43 | |||
|
|
c1e913641e | ||
| 8a14b72c5b |
57 changed files with 2332 additions and 1184 deletions
|
|
@ -1,20 +1,16 @@
|
||||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
|
||||||
# Make sure to check the documentation at https://goreleaser.com
|
|
||||||
|
|
||||||
# The lines below are called `modelines`. See `:help modeline`
|
|
||||||
# Feel free to remove those if you don't want/need to use them.
|
|
||||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
|
env:
|
||||||
|
- GITHUB_TOKEN={{ .Env.CODEBERG_TOKEN }}
|
||||||
|
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
# You may remove this if you don't use go modules.
|
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
# you may remove this if you don't need go generate
|
|
||||||
- go generate ./...
|
- go generate ./...
|
||||||
- go test ./...
|
- go test ./... -v
|
||||||
|
|
||||||
builds:
|
builds:
|
||||||
- env:
|
- env:
|
||||||
|
|
@ -26,7 +22,6 @@ builds:
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- format: tar.gz
|
- format: tar.gz
|
||||||
# this name template makes the OS and Arch compatible with the results of `uname`.
|
|
||||||
name_template: >-
|
name_template: >-
|
||||||
{{ .ProjectName }}_
|
{{ .ProjectName }}_
|
||||||
{{- title .Os }}_
|
{{- title .Os }}_
|
||||||
|
|
@ -34,7 +29,6 @@ archives:
|
||||||
{{- else if eq .Arch "386" }}i386
|
{{- else if eq .Arch "386" }}i386
|
||||||
{{- else }}{{ .Arch }}{{ end }}
|
{{- else }}{{ .Arch }}{{ end }}
|
||||||
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||||
# use zip for windows archives
|
|
||||||
format_overrides:
|
format_overrides:
|
||||||
- goos: windows
|
- goos: windows
|
||||||
format: zip
|
format: zip
|
||||||
|
|
|
||||||
36
cargo.go
36
cargo.go
|
|
@ -1,36 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
type CargoManager struct{}
|
|
||||||
|
|
||||||
func (c *CargoManager) Install(packages []string) error {
|
|
||||||
if len(packages) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := installWithProgress(c, packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CargoManager) Name() string {
|
|
||||||
return "Cargo"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CargoManager) InstallManager() error {
|
|
||||||
if _, err := execLookPath("brew"); err != nil {
|
|
||||||
installHomebrew()
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := execLookPath("cargo"); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := execCommand("brew", "install", "rust")
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CargoManager) InstallPackage(pkg string) error {
|
|
||||||
cmd := execCommand("cargo", "install", pkg)
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
77
changelog.md
77
changelog.md
|
|
@ -2,6 +2,82 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.6.0] - 2025-02-04
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(cli)* Add check command
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- *(packagemanager,cli,tui)* Move packages in specific subfolders
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- *(cli)* Update version
|
||||||
|
|
||||||
|
## [0.5.0] - 2025-01-24
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(cli)* Add concurrent execution of search and update to improve performance
|
||||||
|
- *(cli)* Add aliases to commands
|
||||||
|
- *(config)* Add creation of default config if no config exists
|
||||||
|
- *(cli)* Add history command and logging for actions
|
||||||
|
- *(cli)* Add max history length
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(packagemanager)* Reimplement getPackagemanager to enable installing buildtools on linux
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- *(cli)* Perform code clean up
|
||||||
|
|
||||||
|
## [0.4.0] - 2025-01-20
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(cli)* Add update and update-all command
|
||||||
|
- *(packagemanager)* Added packagemanager definitions for winget and chocolatey
|
||||||
|
- *(cli,packagemanager)* Implemented first working windows and macos versions
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(packagemanager)* Added missing build tag for macos
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog.md
|
||||||
|
- Update changelog.md
|
||||||
|
|
||||||
|
## [0.3.1] - 2025-01-19
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Fix nil pointer execution if no proper packagemanager selected
|
||||||
|
|
||||||
|
## [0.3.0] - 2025-01-18
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(cli)* Implement search argument
|
||||||
|
- *(cli)* Add first implementation for install command
|
||||||
|
- *(cli)* Cleanup install command and add remove and search command
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(cli)* Add missing yes flag in flatpak remove cmd
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- Seperate files, function and structs into seperate packages
|
||||||
|
- Move main.go back to project root
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog.md
|
||||||
|
|
||||||
## [0.2.0] - 2025-01-16
|
## [0.2.0] - 2025-01-16
|
||||||
|
|
||||||
### 🚀 Features
|
### 🚀 Features
|
||||||
|
|
@ -18,6 +94,7 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
### 📚 Documentation
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog.md
|
||||||
- Update changelog.md
|
- Update changelog.md
|
||||||
|
|
||||||
### ⚙️ Miscellaneous Tasks
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
|
||||||
51
cmd.go
51
cmd.go
|
|
@ -1,51 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "system_setup_tool",
|
|
||||||
Short: "Installs packages based on TOML configuration",
|
|
||||||
Run: run,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cobra.OnInitialize(initConfig)
|
|
||||||
rootCmd.PersistentFlags().StringP("config", "c", "", "Path to the configuration file")
|
|
||||||
viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
|
|
||||||
|
|
||||||
addCmd.Flags().StringP("name", "n", "", "The name of the package you want to add")
|
|
||||||
addCmd.Flags().StringP("manager", "m", "", "The package manager you want to add the package to (homebrew|cargo|flatpak|pipx|go)")
|
|
||||||
addCmd.Flags().Bool("system", false, "Add as a system package")
|
|
||||||
addCmd.Flags().Bool("headless", false, "Add as a headless system package (only used with --system)")
|
|
||||||
|
|
||||||
deleteCmd.Flags().StringP("name", "n", "", "The name of the package you want to delete")
|
|
||||||
deleteCmd.Flags().StringP("manager", "m", "", "The package manager you want to delete the package from (homebrew|cargo|flatpak|pipx|go)")
|
|
||||||
deleteCmd.Flags().Bool("system", false, "Delete from system packages")
|
|
||||||
deleteCmd.Flags().Bool("headless", false, "Delete from headless system packages (only used with --system)")
|
|
||||||
|
|
||||||
enableCmd.Flags().Bool("value", true, "Set to true to enable, false to disable")
|
|
||||||
|
|
||||||
packageCmd.AddCommand(addCmd, deleteCmd, showCmd, enableCmd)
|
|
||||||
rootCmd.AddCommand(packageCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initConfig() {
|
|
||||||
if cfgFile := viper.GetString("config"); cfgFile != "" {
|
|
||||||
viper.SetConfigFile(cfgFile)
|
|
||||||
} else {
|
|
||||||
viper.SetConfigName("config")
|
|
||||||
viper.SetConfigType("toml")
|
|
||||||
viper.AddConfigPath(".")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
|
||||||
fmt.Println("Error reading configuration file:", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50
cmd/check_cmd.go
Normal file
50
cmd/check_cmd.go
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var checkCmd = &cobra.Command{
|
||||||
|
Use: "check [package-name]",
|
||||||
|
Short: "Check if the specified package is installed",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
packageName := args[0]
|
||||||
|
managerName, _ := cmd.Flags().GetString("manager")
|
||||||
|
var manager pm.PackageManager
|
||||||
|
switch managerName {
|
||||||
|
case "os":
|
||||||
|
managerName = "OS Package Manager"
|
||||||
|
case "brew":
|
||||||
|
managerName = "homebrew"
|
||||||
|
}
|
||||||
|
switch managerName {
|
||||||
|
case "OS Package Manager":
|
||||||
|
manager = pm.NewOSManager("")
|
||||||
|
case "homebrew":
|
||||||
|
manager = &pm.HomebrewManager{}
|
||||||
|
case "cargo":
|
||||||
|
manager = &pm.CargoManager{}
|
||||||
|
case "pipx":
|
||||||
|
manager = &pm.PipxManager{}
|
||||||
|
case "flatpak":
|
||||||
|
manager = &pm.FlatpakManager{}
|
||||||
|
default:
|
||||||
|
fmt.Println("No PackageManager found")
|
||||||
|
}
|
||||||
|
if err := manager.Check(packageName); err != nil {
|
||||||
|
log.Printf("error: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Package: %s installed\n", packageName)
|
||||||
|
if err := utils.LogToHistory("checked", packageName, manager.Name()); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
141
cmd/cmd.go
Normal file
141
cmd/cmd.go
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/tui"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var RootCmd = &cobra.Command{
|
||||||
|
Use: "system_setup_tool",
|
||||||
|
Short: "Installs packages based on TOML configuration",
|
||||||
|
Version: "0.6.0",
|
||||||
|
Run: tui.Run,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cobra.OnInitialize(initConfig)
|
||||||
|
RootCmd.PersistentFlags().StringP("config", "c", "", "Path to the configuration file")
|
||||||
|
err := viper.BindPFlag("config", RootCmd.PersistentFlags().Lookup("config"))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("could not bind config flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
addCmd.Flags().StringP("name", "n", "", "The name of the package you want to add")
|
||||||
|
addCmd.Flags().StringP("manager", "m", "", "The package manager you want to add the package to (homebrew|cargo|flatpak|pipx|go)")
|
||||||
|
addCmd.Flags().Bool("system", false, "Add as a system package")
|
||||||
|
addCmd.Flags().Bool("headless", false, "Add as a headless system package (only used with --system)")
|
||||||
|
|
||||||
|
deleteCmd.Flags().StringP("name", "n", "", "The name of the package you want to delete")
|
||||||
|
deleteCmd.Flags().StringP("manager", "m", "", "The package manager you want to delete the package from (homebrew|cargo|flatpak|pipx|go)")
|
||||||
|
deleteCmd.Flags().Bool("system", false, "Delete from system packages")
|
||||||
|
deleteCmd.Flags().Bool("headless", false, "Delete from headless system packages (only used with --system)")
|
||||||
|
|
||||||
|
enableCmd.Flags().Bool("value", true, "Set to true to enable, false to disable")
|
||||||
|
|
||||||
|
installCmd.Flags().StringP("manager", "m", "os", "The package manager you want to install a package with. (Options: os|homebrew|pipx|flatpak|cargo)")
|
||||||
|
|
||||||
|
removeCmd.Flags().StringP("manager", "m", "os", "The package manager you want to remove a package with. (Options: os|homebrew|pipx|flatpak|cargo)")
|
||||||
|
|
||||||
|
searchCmd.Flags().StringP("manager", "m", "", "The package manager you want to search a package with. (Options: os|homebrew|flatpak)")
|
||||||
|
|
||||||
|
updateCmd.Flags().StringP("manager", "m", "os", "The package manager you want to update packages with. (Options: os|homebrew|pipx|flatpak)")
|
||||||
|
|
||||||
|
checkCmd.Flags().StringP("manager", "m", "os", "The package manager you want to check for a packages with. (Options: os|homebrew|pipx|flatpak)")
|
||||||
|
|
||||||
|
packageCmd.AddCommand(
|
||||||
|
addCmd,
|
||||||
|
deleteCmd,
|
||||||
|
showCmd,
|
||||||
|
enableCmd,
|
||||||
|
)
|
||||||
|
RootCmd.AddCommand(
|
||||||
|
packageCmd,
|
||||||
|
searchCmd,
|
||||||
|
installCmd,
|
||||||
|
removeCmd,
|
||||||
|
updateCmd,
|
||||||
|
updateAllCmd,
|
||||||
|
historyCmd,
|
||||||
|
checkCmd,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initConfig() {
|
||||||
|
if cfgFile := viper.GetString("config"); cfgFile != "" {
|
||||||
|
viper.SetConfigFile(cfgFile)
|
||||||
|
} else {
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
viper.SetConfigType("toml")
|
||||||
|
dirname, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("cant obtain config dir")
|
||||||
|
} else {
|
||||||
|
viper.AddConfigPath(filepath.Join(dirname, "sst"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||||
|
fmt.Println("no config file found, creating a new one...")
|
||||||
|
if err = createDefaultConfig(); err != nil {
|
||||||
|
slog.Error(fmt.Sprintf("error creating default config: %v\n", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("error reading config file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDefaultConfig() error {
|
||||||
|
v := viper.New()
|
||||||
|
|
||||||
|
v.SetDefault("config", "")
|
||||||
|
v.SetDefault("headless", true)
|
||||||
|
|
||||||
|
v.SetDefault("dotfiles.enable", false)
|
||||||
|
v.SetDefault("dotfiles.git_repo", "")
|
||||||
|
|
||||||
|
v.SetDefault("package_managers.cargo.enable", false)
|
||||||
|
v.SetDefault("package_managers.cargo.packages", []string{})
|
||||||
|
|
||||||
|
v.SetDefault("package_managers.flatpak.enable", false)
|
||||||
|
v.SetDefault("package_managers.flatpak.packages", []string{})
|
||||||
|
|
||||||
|
v.SetDefault("package_managers.go.enable", false)
|
||||||
|
v.SetDefault("package_managers.go.packages", []string{})
|
||||||
|
|
||||||
|
v.SetDefault("package_managers.homebrew.enable", false)
|
||||||
|
v.SetDefault("package_managers.homebrew.packages", []string{})
|
||||||
|
|
||||||
|
v.SetDefault("package_managers.pipx.enable", false)
|
||||||
|
v.SetDefault("package_managers.pipx.packages", []string{})
|
||||||
|
|
||||||
|
v.SetDefault("package_managers.os.enable", true)
|
||||||
|
v.SetDefault("package_managers.os.packages", []string{})
|
||||||
|
|
||||||
|
configDir := filepath.Join(os.Getenv("HOME"), ".config", "sst")
|
||||||
|
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
||||||
|
return fmt.Errorf("error creating config dir: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configPath := filepath.Join(configDir, "config.toml")
|
||||||
|
v.SetConfigFile(configPath)
|
||||||
|
v.SetConfigType("toml")
|
||||||
|
|
||||||
|
if err := v.WriteConfig(); err != nil {
|
||||||
|
return fmt.Errorf("error writing default config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("default config created:", configPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
29
cmd/history_cmd.go
Normal file
29
cmd/history_cmd.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var historyCmd = &cobra.Command{
|
||||||
|
Use: "history",
|
||||||
|
Short: "show command history",
|
||||||
|
Long: "Shows history of the last 2000 commands",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
dirname, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error getting user config dir: %v\n", err)
|
||||||
|
}
|
||||||
|
historyFile := filepath.Join(dirname, "sst", "sst_history")
|
||||||
|
content, err := os.ReadFile(historyFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error reading history: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(content))
|
||||||
|
},
|
||||||
|
}
|
||||||
60
cmd/install_cmd.go
Normal file
60
cmd/install_cmd.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
|
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var installCmd = &cobra.Command{
|
||||||
|
Use: "install [package_name]",
|
||||||
|
Short: "Install a package with the specified package manager",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Aliases: []string{"i"},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
packageName := args[0]
|
||||||
|
managerName, _ := cmd.Flags().GetString("manager")
|
||||||
|
var manager pm.PackageManager
|
||||||
|
switch managerName {
|
||||||
|
case "os":
|
||||||
|
managerName = "OS Package Manager"
|
||||||
|
case "brew":
|
||||||
|
managerName = "homebrew"
|
||||||
|
}
|
||||||
|
switch managerName {
|
||||||
|
case "OS Package Manager":
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
sudoPassword, err := utils.GetSudoPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
manager = pm.NewOSManager(sudoPassword)
|
||||||
|
} else {
|
||||||
|
manager = pm.NewOSManager("")
|
||||||
|
}
|
||||||
|
case "homebrew":
|
||||||
|
manager = &pm.HomebrewManager{}
|
||||||
|
case "cargo":
|
||||||
|
manager = &pm.CargoManager{}
|
||||||
|
case "pipx":
|
||||||
|
manager = &pm.PipxManager{}
|
||||||
|
case "flatpak":
|
||||||
|
manager = &pm.FlatpakManager{}
|
||||||
|
default:
|
||||||
|
fmt.Println("No PackageManager found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := manager.Install([]string{packageName}); err != nil {
|
||||||
|
log.Printf("error: %v\n", err)
|
||||||
|
}
|
||||||
|
if err := utils.LogToHistory("installed", packageName, manager.Name()); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package main
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
@ -31,7 +33,6 @@ var addCmd = &cobra.Command{
|
||||||
packages = viper.GetStringSlice("packages.non_headless")
|
packages = viper.GetStringSlice("packages.non_headless")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add package to the appropriate list
|
|
||||||
packages = append(packages, name)
|
packages = append(packages, name)
|
||||||
|
|
||||||
if isHeadless {
|
if isHeadless {
|
||||||
|
|
@ -42,11 +43,9 @@ var addCmd = &cobra.Command{
|
||||||
} else {
|
} else {
|
||||||
packages := viper.GetStringSlice(fmt.Sprintf("package_managers.%s.packages", manager))
|
packages := viper.GetStringSlice(fmt.Sprintf("package_managers.%s.packages", manager))
|
||||||
|
|
||||||
for _, pkg := range packages {
|
if slices.Contains(packages, name) {
|
||||||
if pkg == name {
|
fmt.Printf("Package %s is already present in the configuration for %s\n", name, manager)
|
||||||
fmt.Printf("Package %s is already present in the configuration for %s\n", name, manager)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
packages = append(packages, name)
|
packages = append(packages, name)
|
||||||
|
|
@ -59,6 +58,9 @@ var addCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Package %s has been added to the configuration for %s\n", name, manager)
|
fmt.Printf("Package %s has been added to the configuration for %s\n", name, manager)
|
||||||
|
if err := utils.LogToHistory("added", name, manager); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +123,9 @@ var deleteCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Package %s was not found in the configuration for %s\n", name, manager)
|
fmt.Printf("Package %s was not found in the configuration for %s\n", name, manager)
|
||||||
|
if err := utils.LogToHistory("removed", name, manager); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -188,5 +193,8 @@ var enableCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Package manager %s has been %s\n", manager, map[bool]string{true: "enabled", false: "disabled"}[enable])
|
fmt.Printf("Package manager %s has been %s\n", manager, map[bool]string{true: "enabled", false: "disabled"}[enable])
|
||||||
|
if err := utils.LogToHistory("enabled", "", manager); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
59
cmd/remove_cmd.go
Normal file
59
cmd/remove_cmd.go
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
|
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var removeCmd = &cobra.Command{
|
||||||
|
Use: "remove [package_name]",
|
||||||
|
Short: "Remove a package with the specified package manager",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
packageName := args[0]
|
||||||
|
managerName, _ := cmd.Flags().GetString("manager")
|
||||||
|
var manager pm.PackageManager
|
||||||
|
switch managerName {
|
||||||
|
case "os":
|
||||||
|
managerName = "OS Package Manager"
|
||||||
|
case "brew":
|
||||||
|
managerName = "homebrew"
|
||||||
|
}
|
||||||
|
switch managerName {
|
||||||
|
case "OS Package Manager":
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
sudoPassword, err := utils.GetSudoPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
manager = pm.NewOSManager(sudoPassword)
|
||||||
|
} else {
|
||||||
|
manager = pm.NewOSManager("")
|
||||||
|
}
|
||||||
|
case "homebrew":
|
||||||
|
manager = &pm.HomebrewManager{}
|
||||||
|
case "cargo":
|
||||||
|
manager = &pm.CargoManager{}
|
||||||
|
case "pipx":
|
||||||
|
manager = &pm.PipxManager{}
|
||||||
|
case "flatpak":
|
||||||
|
manager = &pm.FlatpakManager{}
|
||||||
|
default:
|
||||||
|
fmt.Println("No PackageManager found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := manager.RemovePackage(packageName); err != nil {
|
||||||
|
log.Printf("error: %v\n", err)
|
||||||
|
}
|
||||||
|
if err := utils.LogToHistory("removed", packageName, manager.Name()); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
117
cmd/search_cmd.go
Normal file
117
cmd/search_cmd.go
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var searchCmd = &cobra.Command{
|
||||||
|
Use: "search [package_name]",
|
||||||
|
Short: "Search for a package across package managers (will search in os|flatpak|homebrew)",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
packageName := args[0]
|
||||||
|
managerName, _ := cmd.Flags().GetString("manager")
|
||||||
|
switch managerName {
|
||||||
|
case "os":
|
||||||
|
managerName = "OS Package Manager"
|
||||||
|
case "brew":
|
||||||
|
managerName = "homebrew"
|
||||||
|
}
|
||||||
|
|
||||||
|
var managers []pm.PackageManager
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
managers = []pm.PackageManager{
|
||||||
|
pm.NewOSManager(""),
|
||||||
|
&pm.HomebrewManager{},
|
||||||
|
&pm.FlatpakManager{},
|
||||||
|
}
|
||||||
|
case "windows":
|
||||||
|
managers = []pm.PackageManager{
|
||||||
|
pm.NewOSManager(""),
|
||||||
|
&pm.WingetManager{},
|
||||||
|
&pm.ChocoManager{},
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
managers = []pm.PackageManager{
|
||||||
|
pm.NewOSManager(""),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Println("No Package Managers found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if managerName != "" {
|
||||||
|
for _, m := range managers {
|
||||||
|
if strings.EqualFold(m.Name(), managerName) {
|
||||||
|
searchAndDisplayResults(m, packageName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Not supported for '%s'\n", managerName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
searchConcurrently(managers, packageName)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func displayResults(results []string, manager string) {
|
||||||
|
if len(results) == 0 {
|
||||||
|
fmt.Printf("No results found in %s\n", manager)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, result := range results {
|
||||||
|
fmt.Printf("- %s\n", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchAndDisplayResults(manager pm.PackageManager, packageName string) {
|
||||||
|
fmt.Printf("Searching in %s:\n", manager.Name())
|
||||||
|
results := manager.SearchPackage(packageName)
|
||||||
|
displayResults(results, manager.Name())
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchConcurrently(managers []pm.PackageManager, packageName string) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
results := make(chan struct {
|
||||||
|
manager pm.PackageManager
|
||||||
|
results []string
|
||||||
|
}, len(managers))
|
||||||
|
|
||||||
|
for _, manager := range managers {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(m pm.PackageManager) {
|
||||||
|
defer wg.Done()
|
||||||
|
searchResults := m.SearchPackage(packageName)
|
||||||
|
results <- struct {
|
||||||
|
manager pm.PackageManager
|
||||||
|
results []string
|
||||||
|
}{m, searchResults}
|
||||||
|
}(manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(results)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for result := range results {
|
||||||
|
fmt.Printf("Results from %s:\n", result.manager.Name())
|
||||||
|
displayResults(result.results, result.manager.Name())
|
||||||
|
fmt.Println()
|
||||||
|
if err := utils.LogToHistory("searched", packageName, result.manager.Name()); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
129
cmd/update_command.go
Normal file
129
cmd/update_command.go
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var updateCmd = &cobra.Command{
|
||||||
|
Use: "update [package_name]",
|
||||||
|
Short: "update a package with the specified package manager.",
|
||||||
|
Long: "update a package with the specified package manager.\nIf no package specified, all packages for the package manager will be updated",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Aliases: []string{"u"},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
packageName := args[0]
|
||||||
|
managerName, _ := cmd.Flags().GetString("manager")
|
||||||
|
var manager pm.PackageManager
|
||||||
|
switch managerName {
|
||||||
|
case "os":
|
||||||
|
managerName = "OS Package Manager"
|
||||||
|
case "brew":
|
||||||
|
managerName = "homebrew"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch managerName {
|
||||||
|
case "OS Package Manager":
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
sudoPassword, err := utils.GetSudoPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
manager = pm.NewOSManager(sudoPassword)
|
||||||
|
} else {
|
||||||
|
manager = pm.NewOSManager("")
|
||||||
|
}
|
||||||
|
case "homebrew":
|
||||||
|
manager = &pm.HomebrewManager{}
|
||||||
|
case "cargo":
|
||||||
|
manager = &pm.CargoManager{}
|
||||||
|
case "pipx":
|
||||||
|
manager = &pm.PipxManager{}
|
||||||
|
case "flatpak":
|
||||||
|
manager = &pm.FlatpakManager{}
|
||||||
|
default:
|
||||||
|
fmt.Println("No PackageManager found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if packageName != "" {
|
||||||
|
if err := manager.UpdatePackage(packageName); err != nil {
|
||||||
|
log.Printf("error: %v\n", err)
|
||||||
|
} else {
|
||||||
|
if err := utils.LogToHistory("updated", packageName, manager.Name()); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := manager.UpdateAllPackages(); err != nil {
|
||||||
|
log.Printf("error: %v\n", err)
|
||||||
|
} else {
|
||||||
|
if err := utils.LogToHistory("updated", "all", "all"); err != nil {
|
||||||
|
fmt.Println("error logging action:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateAllCmd = &cobra.Command{
|
||||||
|
Use: "update-all",
|
||||||
|
Short: "update all packages with all package managers.",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
var managers []pm.PackageManager
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
sudoPassword, err := utils.GetSudoPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
managers = []pm.PackageManager{
|
||||||
|
pm.NewOSManager(sudoPassword),
|
||||||
|
&pm.HomebrewManager{},
|
||||||
|
&pm.FlatpakManager{},
|
||||||
|
&pm.PipxManager{},
|
||||||
|
}
|
||||||
|
case "windows":
|
||||||
|
managers = []pm.PackageManager{
|
||||||
|
pm.NewOSManager(""),
|
||||||
|
&pm.WingetManager{},
|
||||||
|
&pm.ChocoManager{},
|
||||||
|
&pm.PipxManager{},
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
sudoPassword, err := utils.GetSudoPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
managers = []pm.PackageManager{
|
||||||
|
pm.NewOSManager(sudoPassword),
|
||||||
|
&pm.PipxManager{},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Println("No Package Managers found")
|
||||||
|
}
|
||||||
|
updateAllConcurrently(managers)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateAllConcurrently(managers []pm.PackageManager) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, m := range managers {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(manager pm.PackageManager) {
|
||||||
|
defer wg.Done()
|
||||||
|
fmt.Printf("Updating %s-Packages\n", manager.Name())
|
||||||
|
err := manager.UpdateAllPackages()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error updating %s: %v\n", manager.Name(), err)
|
||||||
|
}
|
||||||
|
}(m)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
31
config.toml
31
config.toml
|
|
@ -1,31 +0,0 @@
|
||||||
config = ''
|
|
||||||
headless = true
|
|
||||||
|
|
||||||
[dotfiles]
|
|
||||||
enable = false
|
|
||||||
git_repo = 'https://codeberg.org/Pata1704/dotfiles.git'
|
|
||||||
|
|
||||||
[package_managers]
|
|
||||||
[package_managers.cargo]
|
|
||||||
enable = true
|
|
||||||
packages = ['typst-cli']
|
|
||||||
|
|
||||||
[package_managers.flatpak]
|
|
||||||
enable = true
|
|
||||||
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']
|
|
||||||
|
|
||||||
[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']
|
|
||||||
|
|
||||||
[package_managers.homebrew]
|
|
||||||
enable = true
|
|
||||||
packages = ['fd', 'fzf', 'ripgrep', 'neovim', 'helix', 'node', 'yazi', 'zk', 'bat', 'bottom', 'btop', 'git-cliff', 'glow', 'lazygit', 'goreleaser', 'harlequin', 'mage', 'posting', 'typst', 'wails', 'zoxide', 'lsd', 'jq', 'yq', 'timewarrior', 'tmux', 'fastfetch', 'stow', 'distrobox']
|
|
||||||
|
|
||||||
[package_managers.pipx]
|
|
||||||
enable = true
|
|
||||||
packages = ['euporie']
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
headless = ['git', 'curl', 'wget', 'biber', 'bear', 'docker', 'docker-compose', 'zsh', 'npm', 'task', 'tree-sitter-cli', 'python3-pip', 'latexmk', 'luarocks']
|
|
||||||
non_headless = ['flameshot', 'fuzzel', 'hyprcursor', 'hypridle', 'hyprland', 'hyprland-qtutils', 'hyprlock', 'hyprpaper', 'hyprutils', 'kitty', 'mako', 'SwayNotificationCenter', 'SwayNotificationCenter-zsh-completion', 'mpv', 'pidgin', 'remmina', 'thunderbird-i18n-de', 'virt-manager', 'vlc', 'waybar', 'nwg-panel', 'nwg-look', 'xdg-desktop-portal-hyprland', 'zathura', 'zathura-pdf-mupdf']
|
|
||||||
42
dotfiles.go
42
dotfiles.go
|
|
@ -1,42 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DotfilesConfig struct {
|
|
||||||
Enable bool `mapstructure:"enable"`
|
|
||||||
GitRepo string `mapstructure:"git_repo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupDotfiles(config DotfilesConfig) error {
|
|
||||||
if _, err := execLookPath("git"); err != nil {
|
|
||||||
return fmt.Errorf("git ist nicht installiert")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := execLookPath("stow"); err != nil {
|
|
||||||
return fmt.Errorf("gnu stow ist nicht installiert")
|
|
||||||
}
|
|
||||||
|
|
||||||
dotfilesDir := filepath.Join(os.Getenv("HOME"), "dotfiles")
|
|
||||||
|
|
||||||
cmd := execCommand("git", "clone", config.GitRepo, dotfilesDir)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("fehler beim Klonen der Dotfiles: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Chdir(dotfilesDir); err != nil {
|
|
||||||
return fmt.Errorf("fehler beim Wechseln in das Dotfiles-Verzeichnis: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd = execCommand("stow", ".", "--override='*'")
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
log.Printf("Fehler beim Linken: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("Alles erfolgreich verlinkt\n")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
89
flatpak.go
89
flatpak.go
|
|
@ -1,89 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FlatpakManager struct {
|
|
||||||
OS *OS
|
|
||||||
SudoPassword string
|
|
||||||
Config FlatpakConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlatpakManager) Install(packages []string) error {
|
|
||||||
if len(packages) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := installWithProgress(f, packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
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"`
|
|
||||||
Packages []string `mapstructure:"packages"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Remote struct {
|
|
||||||
Name string `mapstructure:"name"`
|
|
||||||
URL string `mapstructure:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func installFlatpak(os *OS, sudoPassword string) error {
|
|
||||||
var command string
|
|
||||||
switch os.PackageManager {
|
|
||||||
case "pacman":
|
|
||||||
command = "pacman -S --noconfirm --needed flatpak"
|
|
||||||
case "apt":
|
|
||||||
command = "apt install -y flatpak"
|
|
||||||
case "dnf":
|
|
||||||
command = "dnf install -y flatpak"
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("keine Flatpak-Installation für OS %s definiert", os.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := installPackage(command, "", sudoPassword); err != nil {
|
|
||||||
return fmt.Errorf("fehler bei der Flatpak-Installation: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addFlatpakRemotes(remotes []Remote) error {
|
|
||||||
for _, remote := range remotes {
|
|
||||||
cmd := execCommand("flatpak", "remote-add", "--if-not-exists", remote.Name, remote.URL)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("fehler beim Hinzufügen des Remotes %s: %v", remote.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlatpakManager) InstallPackage(pkg string) error {
|
|
||||||
cmd := execCommand("flatpak", "install", "-y", pkg)
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
73
go.mod
73
go.mod
|
|
@ -1,60 +1,61 @@
|
||||||
module system_setup_tool
|
module codeberg.org/Pata1704/system_setup_tool
|
||||||
|
|
||||||
go 1.23.4
|
go 1.25.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/charmbracelet/bubbles v0.20.0
|
github.com/charmbracelet/huh v0.8.0
|
||||||
github.com/charmbracelet/bubbletea v1.2.4
|
|
||||||
github.com/charmbracelet/huh v0.6.0
|
|
||||||
github.com/charmbracelet/lipgloss v1.0.0
|
|
||||||
github.com/magefile/mage v1.15.0
|
github.com/magefile/mage v1.15.0
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/schollz/progressbar/v3 v3.18.0
|
github.com/schollz/progressbar/v3 v3.19.0
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.10.2
|
||||||
github.com/spf13/viper v1.19.0
|
github.com/spf13/viper v1.21.0
|
||||||
|
golang.org/x/sys v0.40.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/catppuccin/go v0.2.0 // indirect
|
github.com/catppuccin/go v0.3.0 // indirect
|
||||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
github.com/charmbracelet/bubbletea v1.3.10 // indirect
|
||||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
github.com/charmbracelet/colorprofile v0.4.1 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||||
|
github.com/charmbracelet/x/ansi v0.11.3 // indirect
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20260109001716-2fbdffcb221f // indirect
|
||||||
|
github.com/charmbracelet/x/term v0.2.2 // indirect
|
||||||
|
github.com/clipperhouse/displaywidth v0.6.2 // indirect
|
||||||
|
github.com/clipperhouse/stringish v0.1.1 // indirect
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
|
||||||
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.19 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // 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/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
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.12.0 // indirect
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
github.com/spf13/afero v1.11.0 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
|
||||||
github.com/stretchr/testify v1.10.0 // indirect
|
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/sync v0.9.0 // indirect
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||||
golang.org/x/sys v0.29.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/term v0.28.0 // indirect
|
golang.org/x/term v0.39.0 // indirect
|
||||||
golang.org/x/text v0.18.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // 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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
199
go.sum
199
go.sum
|
|
@ -4,43 +4,81 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
|
||||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
|
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||||
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||||
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
|
||||||
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
|
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||||
github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE=
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM=
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws=
|
||||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7/go.mod h1:ISC1gtLcVilLOf23wvTfoQuYbW2q0JevFxPfUzZ9Ybw=
|
||||||
github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8=
|
github.com/charmbracelet/bubbletea v1.3.5 h1:JAMNLTbqMOhSwoELIr0qyP4VidFq72/6E9j7HHmRKQc=
|
||||||
github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU=
|
github.com/charmbracelet/bubbletea v1.3.5/go.mod h1:TkCnmH+aBd4LrXhXcqrKiYwRs7qyQx5rBgH5fVY3v54=
|
||||||
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
|
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||||
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
|
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||||
github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM=
|
github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40=
|
||||||
github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0=
|
||||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4=
|
github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
|
||||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
|
||||||
|
github.com/charmbracelet/huh v0.7.0 h1:W8S1uyGETgj9Tuda3/JdVkc3x7DBLZYPZc4c+/rnRdc=
|
||||||
|
github.com/charmbracelet/huh v0.7.0/go.mod h1:UGC3DZHlgOKHvHC07a5vHag41zzhpPFj34U92sOmyuk=
|
||||||
|
github.com/charmbracelet/huh v0.8.0 h1:Xz/Pm2h64cXQZn/Jvele4J3r7DDiqFCNIVteYukxDvY=
|
||||||
|
github.com/charmbracelet/huh v0.8.0/go.mod h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4=
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
|
github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
|
||||||
|
github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
||||||
|
github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI=
|
||||||
|
github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
|
||||||
|
github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U=
|
||||||
|
github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ=
|
||||||
|
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA=
|
||||||
|
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20250623112707-45752038d08d h1:fEsdno3tFo//l8pS4hlzH5hj6zGSaMzQcbyDLfToeJg=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20250623112707-45752038d08d/go.mod h1:Rgw3/F+xlcUc5XygUtimVSxAqCOsqyvJjqF5UHRvc5k=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20260109001716-2fbdffcb221f h1:c0cKImYFPrOEEzMsYss56Q7Q69HD7H4ss3Yu9Mw9vqQ=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20260109001716-2fbdffcb221f/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
|
||||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||||
|
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||||
|
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||||
|
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
|
||||||
|
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
|
||||||
|
github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI=
|
||||||
|
github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4=
|
||||||
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
||||||
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
||||||
|
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
||||||
|
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
|
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
|
@ -52,16 +90,18 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
|
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
|
||||||
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
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/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
||||||
|
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
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/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=
|
||||||
|
|
@ -72,71 +112,82 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
|
||||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
|
||||||
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
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/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||||
|
github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc=
|
||||||
|
github.com/schollz/progressbar/v3 v3.19.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/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
||||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
|
||||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||||
|
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||||
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
|
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||||
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
|
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/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.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||||
|
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||||
|
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||||
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
|
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||||
|
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
||||||
36
golang.go
36
golang.go
|
|
@ -1,36 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
type GolangManager struct{}
|
|
||||||
|
|
||||||
func (g *GolangManager) Install(packages []string) error {
|
|
||||||
if len(packages) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := installWithProgress(g, packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GolangManager) Name() string {
|
|
||||||
return "Golang"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GolangManager) InstallManager() error {
|
|
||||||
if _, err := execLookPath("brew"); err != nil {
|
|
||||||
installHomebrew()
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := execLookPath("go"); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := execCommand("brew", "install", "golang")
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GolangManager) InstallPackage(pkg string) error {
|
|
||||||
cmd := execCommand("go", "install", pkg+"@latest")
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
43
homebrew.go
43
homebrew.go
|
|
@ -1,43 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HomebrewManager struct{}
|
|
||||||
|
|
||||||
func (h *HomebrewManager) Install(packages []string) error {
|
|
||||||
if len(packages) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := installWithProgress(h, packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HomebrewManager) Name() string {
|
|
||||||
return "Homebrew"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HomebrewManager) InstallManager() error {
|
|
||||||
if _, err := execLookPath("brew"); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return installHomebrew()
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (h *HomebrewManager) InstallPackage(pkg string) error {
|
|
||||||
cmd := execCommand("brew", "install", pkg)
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
package main
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/dotfiles"
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
)
|
||||||
|
|
||||||
type PackageManagerConfig struct {
|
type PackageManagerConfig struct {
|
||||||
Enable bool `mapstructure:"enable"`
|
Enable bool `mapstructure:"enable"`
|
||||||
|
|
@ -7,7 +12,7 @@ type PackageManagerConfig struct {
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Headless bool `mapstructure:"headless"`
|
Headless bool `mapstructure:"headless"`
|
||||||
Packages Packages `mapstructure:"packages"`
|
Packages pm.Packages `mapstructure:"packages"`
|
||||||
PackageManagers map[string]PackageManagerConfig `mapstructure:"package_managers"`
|
PackageManagers map[string]PackageManagerConfig `mapstructure:"package_managers"`
|
||||||
Dotfiles DotfilesConfig `mapstructure:"dotfiles"`
|
Dotfiles dotfiles.DotfilesConfig `mapstructure:"dotfiles"`
|
||||||
}
|
}
|
||||||
43
internal/dotfiles/dotfiles.go
Normal file
43
internal/dotfiles/dotfiles.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package dotfiles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DotfilesConfig struct {
|
||||||
|
Enable bool `mapstructure:"enable"`
|
||||||
|
GitRepo string `mapstructure:"git_repo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupDotfiles(config DotfilesConfig) error {
|
||||||
|
if _, err := shell.ExecLookPath("git"); err != nil {
|
||||||
|
return fmt.Errorf("git ist nicht installiert")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := shell.ExecLookPath("stow"); err != nil {
|
||||||
|
return fmt.Errorf("gnu stow not installed")
|
||||||
|
}
|
||||||
|
|
||||||
|
dotfilesDir := filepath.Join(os.Getenv("HOME"), "dotfiles")
|
||||||
|
|
||||||
|
cmd := shell.ExecCommand("git", "clone", config.GitRepo, dotfilesDir)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("error cloning dotfiles: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Chdir(dotfilesDir); err != nil {
|
||||||
|
return fmt.Errorf("error changing into dotfiles directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = shell.ExecCommand("stow", ".", "--override='*'")
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Printf("error creating links: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("all linked properly\n")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
23
internal/shell/shell.go
Normal file
23
internal/shell/shell.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package shell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ExecCommand = exec.Command
|
||||||
|
ExecLookPath = exec.LookPath
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExecuteShellCommand(command string, env string) error {
|
||||||
|
cmd := ExecCommand("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
|
||||||
|
}
|
||||||
115
internal/tui/tui.go
Normal file
115
internal/tui/tui.go
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
package tui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/config"
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/dotfiles"
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/utils"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
pm "codeberg.org/Pata1704/system_setup_tool/pkg/packagemanager"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type installedPkgMsg string
|
||||||
|
|
||||||
|
func Run(cmd *cobra.Command, args []string) {
|
||||||
|
sudoPassword, err := utils.GetSudoPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg config.Config
|
||||||
|
if err := viper.Unmarshal(&cfg); err != nil {
|
||||||
|
log.Fatalf("Fehler beim Lesen der Konfiguration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// form := huh.NewForm(
|
||||||
|
// huh.NewGroup(
|
||||||
|
// huh.NewConfirm().
|
||||||
|
// Title("Möchten Sie eine headless Installation durchführen?").
|
||||||
|
// Value(&cfg.Headless),
|
||||||
|
// ),
|
||||||
|
// ).WithTheme(huh.ThemeCatppuccin())
|
||||||
|
//
|
||||||
|
// if err := form.Run(); err != nil {
|
||||||
|
// log.Fatalf("Fehler bei der Benutzerabfrage: %v", err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// osManager := pm.NewOSManager(sudoPassword)
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
for name, config := range cfg.PackageManagers {
|
||||||
|
if config.Enable {
|
||||||
|
var manager pm.PackageManager
|
||||||
|
switch name {
|
||||||
|
case "os":
|
||||||
|
manager = pm.NewOSManager(sudoPassword)
|
||||||
|
case "homebrew":
|
||||||
|
manager = &pm.HomebrewManager{}
|
||||||
|
case "go":
|
||||||
|
manager = &pm.GolangManager{}
|
||||||
|
case "cargo":
|
||||||
|
manager = &pm.CargoManager{}
|
||||||
|
case "pipx":
|
||||||
|
manager = &pm.PipxManager{}
|
||||||
|
case "flatpak":
|
||||||
|
flatpakConfig := pm.FlatpakConfig{}
|
||||||
|
if err := mapstructure.Decode(config, &flatpakConfig); err != nil {
|
||||||
|
log.Printf("error decoding flatpak config: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
manager = pm.NewFlatpakManager(sudoPassword, flatpakConfig)
|
||||||
|
default:
|
||||||
|
log.Printf("unknown packagemanager: %s", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := manager.InstallManager(); err != nil {
|
||||||
|
log.Printf("warning packagemanager %s not installed and could not be installed: %v", manager.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := manager.Install(config.Packages); err != nil {
|
||||||
|
log.Printf("warning at %s-packages: %v", manager.Name(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osManager := pm.NewOSManager(sudoPassword)
|
||||||
|
var installBuild bool
|
||||||
|
form := huh.NewForm(
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewConfirm().
|
||||||
|
Title("Möchten Sie die Build Essentials installieren?").
|
||||||
|
Value(&installBuild),
|
||||||
|
),
|
||||||
|
).WithTheme(huh.ThemeCatppuccin())
|
||||||
|
|
||||||
|
err = form.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if installBuild {
|
||||||
|
if err := osManager.InstallBuildEssentials(); err != nil {
|
||||||
|
log.Printf("Warnung: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.Dotfiles.Enable {
|
||||||
|
fmt.Println("\nconfiguring dotfiles...")
|
||||||
|
if err := dotfiles.SetupDotfiles(cfg.Dotfiles); err != nil {
|
||||||
|
log.Printf("Warnung bei Dotfiles-Setup: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
internal/utils/utils.go
Normal file
80
internal/utils/utils.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSudoPassword() (string, error) {
|
||||||
|
var password string
|
||||||
|
form := huh.NewForm(
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewInput().
|
||||||
|
Title("Enter your password").
|
||||||
|
EchoMode(huh.EchoModePassword).
|
||||||
|
Value(&password),
|
||||||
|
),
|
||||||
|
).WithTheme(huh.ThemeCatppuccin())
|
||||||
|
|
||||||
|
err := form.Run()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error at password-dialog: %v", err)
|
||||||
|
}
|
||||||
|
return password, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxHistoryLines = 2000
|
||||||
|
historyFileName = "sst_history"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LogToHistory(action, pkg, manager string) error {
|
||||||
|
dirname, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cant obtain config dir: %v", err)
|
||||||
|
}
|
||||||
|
historyFile := filepath.Join(dirname, "sst", historyFileName)
|
||||||
|
|
||||||
|
lines, err := readHistoryLines(historyFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
logEntry := fmt.Sprintf("%s: action: [%s] - package: [%s] - packagemanager: [%s]", timestamp, action, pkg, manager)
|
||||||
|
lines = append(lines, logEntry)
|
||||||
|
|
||||||
|
if len(lines) > maxHistoryLines {
|
||||||
|
lines = lines[len(lines)-maxHistoryLines:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeHistoryLines(historyFile, lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readHistoryLines(filePath string) ([]string, error) {
|
||||||
|
content, err := os.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return strings.Split(string(content), "\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeHistoryLines(filePath string, lines []string) error {
|
||||||
|
content := strings.Join(lines, "\n")
|
||||||
|
return os.WriteFile(filePath, []byte(content), 0644)
|
||||||
|
}
|
||||||
40
internal/utils/utils_test.go
Normal file
40
internal/utils/utils_test.go
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"os/exec"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMax(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
a, b, want int
|
||||||
|
}{
|
||||||
|
{1, 2, 2},
|
||||||
|
{5, 3, 5},
|
||||||
|
{0, 0, 0},
|
||||||
|
{-1, -5, -1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := max(tt.a, tt.b)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("max(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteShellCommand(t *testing.T) {
|
||||||
|
// Mock execCommand
|
||||||
|
oldExecCommand := shell.ExecCommand
|
||||||
|
defer func() { shell.ExecCommand = oldExecCommand }()
|
||||||
|
|
||||||
|
shell.ExecCommand = func(command string, args ...string) *exec.Cmd {
|
||||||
|
return exec.Command("echo", "mocked command")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := shell.ExecuteShellCommand("test command", "TEST_ENV=value")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("executeShellCommand() error = %v; want nil", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
magefile.go
15
magefile.go
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build mage
|
//go:build mage
|
||||||
// +build mage
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
@ -17,9 +16,8 @@ import (
|
||||||
|
|
||||||
// A build step that requires additional params, or platform specific steps for example
|
// A build step that requires additional params, or platform specific steps for example
|
||||||
func Build() error {
|
func Build() error {
|
||||||
mg.Deps(InstallDeps)
|
|
||||||
fmt.Println("Building...")
|
fmt.Println("Building...")
|
||||||
cmd := exec.Command("go", "build", "-o", "system_setup_tool", ".")
|
cmd := exec.Command("go", "build", "-o", "sst", ".")
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,20 +25,13 @@ func Build() error {
|
||||||
func Install() error {
|
func Install() error {
|
||||||
mg.Deps(Build)
|
mg.Deps(Build)
|
||||||
fmt.Println("Installing...")
|
fmt.Println("Installing...")
|
||||||
return os.Rename("./system_setup_tool", "/usr/bin/system_setup_tool")
|
return os.Rename("./sst", "~/.local/bin/sst")
|
||||||
}
|
|
||||||
|
|
||||||
// Manage your deps, or running package managers.
|
|
||||||
func InstallDeps() error {
|
|
||||||
fmt.Println("Installing Deps...")
|
|
||||||
cmd := exec.Command("go", "get", "github.com/stretchr/piglatin")
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up after yourself
|
// Clean up after yourself
|
||||||
func Clean() {
|
func Clean() {
|
||||||
fmt.Println("Cleaning...")
|
fmt.Println("Cleaning...")
|
||||||
os.RemoveAll("MyApp")
|
os.RemoveAll("system_setup_tool")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use gofmt to format your code
|
// Use gofmt to format your code
|
||||||
|
|
|
||||||
4
main.go
4
main.go
|
|
@ -3,10 +3,12 @@ package main
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := cmd.RootCmd.Execute(); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
164
model.go
164
model.go
|
|
@ -1,164 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/progress"
|
|
||||||
"github.com/charmbracelet/bubbles/spinner"
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
|
||||||
)
|
|
||||||
|
|
||||||
type model struct {
|
|
||||||
packages []string
|
|
||||||
index int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
spinner spinner.Model
|
|
||||||
progress progress.Model
|
|
||||||
done bool
|
|
||||||
sudoPassword string
|
|
||||||
os OS
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) installSpecialSoftware() error {
|
|
||||||
if _, err := execLookPath("oh-my-posh"); err == nil {
|
|
||||||
fmt.Println("Oh-my-posh ist bereits installiert")
|
|
||||||
} else {
|
|
||||||
poshCommand := "curl -s https://ohmyposh.dev/install.sh | bash -s"
|
|
||||||
if err := installPackage(poshCommand, "", ""); 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
|
|
||||||
}
|
|
||||||
|
|
||||||
func newModel(packages []string, sudoPassword string, os *OS) model {
|
|
||||||
p := progress.New(
|
|
||||||
progress.WithDefaultGradient(),
|
|
||||||
progress.WithWidth(40),
|
|
||||||
progress.WithoutPercentage(),
|
|
||||||
)
|
|
||||||
s := spinner.New()
|
|
||||||
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("63"))
|
|
||||||
return model{
|
|
||||||
packages: packages,
|
|
||||||
spinner: s,
|
|
||||||
progress: p,
|
|
||||||
sudoPassword: sudoPassword,
|
|
||||||
os: *os,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
|
||||||
return tea.Batch(m.installPackageCmd(m.packages[m.index]), m.spinner.Tick)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case tea.WindowSizeMsg:
|
|
||||||
m.width, m.height = msg.Width, msg.Height
|
|
||||||
case tea.KeyMsg:
|
|
||||||
switch msg.String() {
|
|
||||||
case "ctrl+c", "esc", "q":
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
case installedPkgMsg:
|
|
||||||
pkg := m.packages[m.index]
|
|
||||||
if m.index >= len(m.packages)-1 {
|
|
||||||
m.done = true
|
|
||||||
return m, tea.Sequence(
|
|
||||||
tea.Printf("%s %s", checkMark, pkg),
|
|
||||||
tea.Quit,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
m.index++
|
|
||||||
progressCmd := m.progress.SetPercent(float64(m.index) / float64(len(m.packages)))
|
|
||||||
|
|
||||||
return m, tea.Batch(
|
|
||||||
progressCmd,
|
|
||||||
tea.Printf("%s %s", checkMark, pkg),
|
|
||||||
m.installPackageCmd(m.packages[m.index]),
|
|
||||||
)
|
|
||||||
case spinner.TickMsg:
|
|
||||||
var cmd tea.Cmd
|
|
||||||
m.spinner, cmd = m.spinner.Update(msg)
|
|
||||||
return m, cmd
|
|
||||||
case progress.FrameMsg:
|
|
||||||
newModel, cmd := m.progress.Update(msg)
|
|
||||||
if newModel, ok := newModel.(progress.Model); ok {
|
|
||||||
m.progress = newModel
|
|
||||||
}
|
|
||||||
return m, cmd
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) View() string {
|
|
||||||
n := len(m.packages)
|
|
||||||
w := lipgloss.Width(fmt.Sprintf("%d", n))
|
|
||||||
|
|
||||||
if m.done {
|
|
||||||
return doneStyle.Render(fmt.Sprintf("Done! Installed %d packages.\n", n))
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgCount := fmt.Sprintf(" %*d/%*d", w, m.index, w, n)
|
|
||||||
|
|
||||||
spin := m.spinner.View() + " "
|
|
||||||
prog := m.progress.View()
|
|
||||||
cellsAvail := max(0, m.width-lipgloss.Width(spin+prog+pkgCount))
|
|
||||||
|
|
||||||
pkgName := currentPkgNameStyle.Render(m.packages[m.index])
|
|
||||||
info := lipgloss.NewStyle().MaxWidth(cellsAvail).Render("Installing " + pkgName)
|
|
||||||
|
|
||||||
cellsRemaining := max(0, m.width-lipgloss.Width(spin+info+prog+pkgCount))
|
|
||||||
gap := strings.Repeat(" ", cellsRemaining)
|
|
||||||
|
|
||||||
return spin + info + gap + prog + pkgCount
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) installPackageCmd(pkg string) tea.Cmd {
|
|
||||||
return func() tea.Msg {
|
|
||||||
if err := installPackage(m.os.InstallCommand, pkg, m.sudoPassword); err != nil {
|
|
||||||
log.Printf("Fehler beim Installieren von %s: %v", pkg, err)
|
|
||||||
}
|
|
||||||
return installedPkgMsg(pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
166
osinfo.go
166
osinfo.go
|
|
@ -1,166 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"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
|
|
||||||
Version string
|
|
||||||
PackageManager string
|
|
||||||
InstallCommand string
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseOsRelease(osRelease string) *OS {
|
|
||||||
var result OS
|
|
||||||
result.ID = "Unknown"
|
|
||||||
result.Name = "Unknown"
|
|
||||||
result.Version = "Unknown"
|
|
||||||
result.PackageManager = "Unkown"
|
|
||||||
result.InstallCommand = "Unkown"
|
|
||||||
|
|
||||||
lines := strings.Split(osRelease, "\n")
|
|
||||||
|
|
||||||
for _, line := range lines {
|
|
||||||
splitLine := strings.SplitN(line, "=", 2)
|
|
||||||
if len(splitLine) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch splitLine[0] {
|
|
||||||
case "ID":
|
|
||||||
result.ID = strings.ToLower(strings.Trim(splitLine[1], "\""))
|
|
||||||
case "NAME":
|
|
||||||
result.Name = strings.Trim(splitLine[1], "\"")
|
|
||||||
case "VERSION_ID":
|
|
||||||
result.Version = strings.Trim(splitLine[1], "\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := result.getPackageManager()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = result.getInstallCommand()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLinuxDistribution() (*OS, error) {
|
|
||||||
_, err := os.Stat("/etc/os-release")
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil, fmt.Errorf("unable to read system information")
|
|
||||||
}
|
|
||||||
|
|
||||||
osRelease, _ := os.ReadFile("/etc/os-release")
|
|
||||||
return parseOsRelease(string(osRelease)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (os *OS) getPackageManager() error {
|
|
||||||
switch os.ID {
|
|
||||||
case "debian", "ubuntu":
|
|
||||||
os.PackageManager = "apt"
|
|
||||||
return nil
|
|
||||||
case "arch":
|
|
||||||
os.PackageManager = "pacman"
|
|
||||||
return nil
|
|
||||||
case "fedora":
|
|
||||||
os.PackageManager = "dnf"
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
pmcommands := []string{
|
|
||||||
"apt",
|
|
||||||
"dnf",
|
|
||||||
"pacman",
|
|
||||||
}
|
|
||||||
for _, pmname := range pmcommands {
|
|
||||||
_, err := execLookPath(pmname)
|
|
||||||
if err == nil {
|
|
||||||
os.PackageManager = pmname
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("no packagemanager found for os: %s", os)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (os *OS) getInstallCommand() error {
|
|
||||||
switch os.PackageManager {
|
|
||||||
case "apt":
|
|
||||||
os.InstallCommand = "apt install -y"
|
|
||||||
return nil
|
|
||||||
case "pacman":
|
|
||||||
os.InstallCommand = "pacman -S --noconfirm --needed"
|
|
||||||
return nil
|
|
||||||
case "dnf":
|
|
||||||
os.InstallCommand = "dnf install -y --best"
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("no install command found for package manager: %s", os.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func installBuildEssentials(os *OS, sudoPassword string) error {
|
|
||||||
var command string
|
|
||||||
switch os.PackageManager {
|
|
||||||
case "pacman":
|
|
||||||
command = "pacman -S --noconfirm --needed base-devel"
|
|
||||||
case "apt":
|
|
||||||
command = "apt install -y build-essential"
|
|
||||||
case "dnf":
|
|
||||||
command = "dnf install -y @development-tools"
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("keine Build Essentials für OS %s definiert", os.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Installiere Build Essentials für %s...\n", os.Name)
|
|
||||||
if err := installPackage(command, "", sudoPassword); err != nil {
|
|
||||||
return fmt.Errorf("fehler bei der Installation der Build Essentials: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
type PackageManager interface {
|
|
||||||
Install(packages []string) error
|
|
||||||
InstallPackage(pkg string) error
|
|
||||||
InstallManager() error
|
|
||||||
Name() string
|
|
||||||
}
|
|
||||||
37
pipx.go
37
pipx.go
|
|
@ -1,37 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
type PipxManager struct{}
|
|
||||||
|
|
||||||
func (p *PipxManager) Install(packages []string) error {
|
|
||||||
if len(packages) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := installWithProgress(p, packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipxManager) Name() string {
|
|
||||||
return "Pipx"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipxManager) InstallManager() error {
|
|
||||||
if _, err := execLookPath("brew"); err != nil {
|
|
||||||
installHomebrew()
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := execLookPath("pipx"); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := execCommand("brew", "install", "pipx")
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipxManager) InstallPackage(pkg string) error {
|
|
||||||
cmd := execCommand("pipx", "install", pkg)
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
81
pkg/packagemanager/apt.go
Normal file
81
pkg/packagemanager/apt.go
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AptManager struct {
|
||||||
|
SudoPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(a, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) Name() string {
|
||||||
|
return "OS Home Manager"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) InstallManager() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := "apt install -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := "apt remove -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := "apt search -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
|
||||||
|
packages, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", a.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := "apt update -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) UpdateAllPackages() error {
|
||||||
|
cmd := "apt update -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s", cmd)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(a.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AptManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("dpkg -l | grep %s", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
69
pkg/packagemanager/cargo.go
Normal file
69
pkg/packagemanager/cargo.go
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CargoManager struct{}
|
||||||
|
|
||||||
|
func (c *CargoManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(c, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) Name() string {
|
||||||
|
return "Cargo"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("brew"); err != nil {
|
||||||
|
installHomebrew()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := shell.ExecLookPath("cargo"); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := shell.ExecCommand("brew", "install", "rust")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("cargo", "install", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("cargo", "uninstall", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) SearchPackage(pkg string) []string {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) UpdatePackage(pkg string) error {
|
||||||
|
return fmt.Errorf("update not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) UpdateAllPackages() error {
|
||||||
|
return fmt.Errorf("update not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CargoManager) Check(pkg string) error {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmd := shell.ExecCommand("ls", filepath.Join(home, ".cargo", "bin", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// cargo_test.go
|
// cargo_test.go
|
||||||
package main
|
package packagemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -17,13 +18,13 @@ func TestCargoManager_InstallManager(t *testing.T) {
|
||||||
cm := &CargoManager{}
|
cm := &CargoManager{}
|
||||||
|
|
||||||
// Mock exec.LookPath
|
// Mock exec.LookPath
|
||||||
execLookPath = func(file string) (string, error) {
|
shell.ExecLookPath = func(file string) (string, error) {
|
||||||
if file == "cargo" {
|
if file == "cargo" {
|
||||||
return "/usr/bin/cargo", nil
|
return "/usr/bin/cargo", nil
|
||||||
}
|
}
|
||||||
return "", exec.ErrNotFound
|
return "", exec.ErrNotFound
|
||||||
}
|
}
|
||||||
defer func() { execLookPath = exec.LookPath }()
|
defer func() { shell.ExecLookPath = exec.LookPath }()
|
||||||
|
|
||||||
if err := cm.InstallManager(); err != nil {
|
if err := cm.InstallManager(); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
|
@ -34,10 +35,10 @@ func TestCargoManager_InstallPackage(t *testing.T) {
|
||||||
cm := &CargoManager{}
|
cm := &CargoManager{}
|
||||||
|
|
||||||
// Mock exec.Command
|
// Mock exec.Command
|
||||||
execCommand = func(name string, arg ...string) *exec.Cmd {
|
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
|
||||||
return exec.Command("echo", "mocked cargo install")
|
return exec.Command("echo", "mocked cargo install")
|
||||||
}
|
}
|
||||||
defer func() { execCommand = exec.Command }()
|
defer func() { shell.ExecCommand = exec.Command }()
|
||||||
|
|
||||||
if err := cm.InstallPackage("test-package"); err != nil {
|
if err := cm.InstallPackage("test-package"); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
71
pkg/packagemanager/choco.go
Normal file
71
pkg/packagemanager/choco.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChocoManager struct{}
|
||||||
|
|
||||||
|
func (c *ChocoManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(c, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) Name() string {
|
||||||
|
return "Chocolatey"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("choco"); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return installHomebrew()
|
||||||
|
}
|
||||||
|
|
||||||
|
func installChoco() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("choco", "install", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("choco", "uninstall", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := shell.ExecCommand("choco", "search", pkg)
|
||||||
|
packages, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", c.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("choco", "update", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) UpdateAllPackages() error {
|
||||||
|
cmd := shell.ExecCommand("choco", "update")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChocoManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("choco", "search", "--local-only", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
78
pkg/packagemanager/dnf.go
Normal file
78
pkg/packagemanager/dnf.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DnfManager struct {
|
||||||
|
SudoPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(d, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) Name() string {
|
||||||
|
return "OS Home Manager"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) InstallManager() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := "dnf install -y --best"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := "dnf remove -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := shell.ExecCommand("dnf", "search", pkg)
|
||||||
|
packages, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", d.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := "dnf update -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) UpdateAllPackages() error {
|
||||||
|
cmd := "dnf update -y"
|
||||||
|
fullCmd := fmt.Sprintf("%s", cmd)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(d.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DnfManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("dnf list installed | grep %s", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
133
pkg/packagemanager/flatpak.go
Normal file
133
pkg/packagemanager/flatpak.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FlatpakManager struct {
|
||||||
|
OS *OS
|
||||||
|
SudoPassword string
|
||||||
|
Config FlatpakConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFlatpakManager(sudoPassword string, config FlatpakConfig) *FlatpakManager {
|
||||||
|
os, err := GetLinuxDistribution()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error geting os information: %v", err)
|
||||||
|
}
|
||||||
|
return &FlatpakManager{
|
||||||
|
OS: os,
|
||||||
|
SudoPassword: sudoPassword,
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(f, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) Name() string {
|
||||||
|
return "Flatpak"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("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"`
|
||||||
|
Packages []string `mapstructure:"packages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Remote struct {
|
||||||
|
Name string `mapstructure:"name"`
|
||||||
|
URL string `mapstructure:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func installFlatpak(os *OS, sudoPassword string) error {
|
||||||
|
var command string
|
||||||
|
switch os.PackageManager {
|
||||||
|
case "pacman":
|
||||||
|
command = "pacman -S --noconfirm --needed flatpak"
|
||||||
|
case "apt":
|
||||||
|
command = "apt install -y flatpak"
|
||||||
|
case "dnf":
|
||||||
|
command = "dnf install -y flatpak"
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("keine Flatpak-Installation für OS %s definiert", os.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := InstallPackage(command, "", sudoPassword); err != nil {
|
||||||
|
return fmt.Errorf("fehler bei der Flatpak-Installation: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFlatpakRemotes(remotes []Remote) error {
|
||||||
|
for _, remote := range remotes {
|
||||||
|
cmd := shell.ExecCommand("flatpak", "remote-add", "--if-not-exists", remote.Name, remote.URL)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("fehler beim Hinzufügen des Remotes %s: %v", remote.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("flatpak", "install", "-y", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("flatpak", "uninstall", "-y", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := shell.ExecCommand("flatpak", "search", pkg)
|
||||||
|
packages, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", f.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("flatpak", "update", "-y", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) UpdateAllPackages() error {
|
||||||
|
cmd := shell.ExecCommand("flatpak", "update", "-y")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlatpakManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("flatpak list | grep %s", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// flatpak_test.go
|
package packagemanager
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -33,10 +33,10 @@ func TestFlatpakManager_InstallPackage(t *testing.T) {
|
||||||
fm := &FlatpakManager{}
|
fm := &FlatpakManager{}
|
||||||
|
|
||||||
// Mock exec.Command
|
// Mock exec.Command
|
||||||
execCommand = func(name string, arg ...string) *exec.Cmd {
|
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
|
||||||
return exec.Command("echo", "mocked flatpak install")
|
return exec.Command("echo", "mocked flatpak install")
|
||||||
}
|
}
|
||||||
defer func() { execCommand = exec.Command }()
|
defer func() { shell.ExecCommand = exec.Command }()
|
||||||
|
|
||||||
if err := fm.InstallPackage("test-package"); err != nil {
|
if err := fm.InstallPackage("test-package"); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
69
pkg/packagemanager/golang.go
Normal file
69
pkg/packagemanager/golang.go
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GolangManager struct{}
|
||||||
|
|
||||||
|
func (g *GolangManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(g, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) Name() string {
|
||||||
|
return "Golang"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("brew"); err != nil {
|
||||||
|
installHomebrew()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := shell.ExecLookPath("go"); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := shell.ExecCommand("brew", "install", "golang")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("go", "install", pkg+"@latest")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("go", "uninstall", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) SearchPackage(pkg string) []string {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) UpdatePackage(pkg string) error {
|
||||||
|
return fmt.Errorf("update not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) UpdateAllPackages() error {
|
||||||
|
return fmt.Errorf("update not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GolangManager) Check(pkg string) error {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error: %v\n", err)
|
||||||
|
}
|
||||||
|
cmd := shell.ExecCommand("ls", filepath.Join(home, "go", "bin", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// golang_test.go
|
package packagemanager
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -17,13 +17,13 @@ func TestGolangManager_InstallManager(t *testing.T) {
|
||||||
gm := &GolangManager{}
|
gm := &GolangManager{}
|
||||||
|
|
||||||
// Mock exec.LookPath
|
// Mock exec.LookPath
|
||||||
execLookPath = func(file string) (string, error) {
|
shell.ExecLookPath = func(file string) (string, error) {
|
||||||
if file == "go" {
|
if file == "go" {
|
||||||
return "/usr/local/go/bin/go", nil
|
return "/usr/local/go/bin/go", nil
|
||||||
}
|
}
|
||||||
return "", exec.ErrNotFound
|
return "", exec.ErrNotFound
|
||||||
}
|
}
|
||||||
defer func() { execLookPath = exec.LookPath }()
|
defer func() { shell.ExecLookPath = exec.LookPath }()
|
||||||
|
|
||||||
if err := gm.InstallManager(); err != nil {
|
if err := gm.InstallManager(); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
|
@ -34,10 +34,10 @@ func TestGolangManager_InstallPackage(t *testing.T) {
|
||||||
gm := &GolangManager{}
|
gm := &GolangManager{}
|
||||||
|
|
||||||
// Mock exec.Command
|
// Mock exec.Command
|
||||||
execCommand = func(name string, arg ...string) *exec.Cmd {
|
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
|
||||||
return exec.Command("echo", "mocked go install")
|
return exec.Command("echo", "mocked go install")
|
||||||
}
|
}
|
||||||
defer func() { execCommand = exec.Command }()
|
defer func() { shell.ExecCommand = exec.Command }()
|
||||||
|
|
||||||
if err := gm.InstallPackage("github.com/test/package"); err != nil {
|
if err := gm.InstallPackage("github.com/test/package"); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
76
pkg/packagemanager/homebrew.go
Normal file
76
pkg/packagemanager/homebrew.go
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HomebrewManager struct{}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(h, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) Name() string {
|
||||||
|
return "Homebrew"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("brew"); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return installHomebrew()
|
||||||
|
}
|
||||||
|
|
||||||
|
func installHomebrew() error {
|
||||||
|
err := shell.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 (h *HomebrewManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("brew", "install", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("brew", "uninstall", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := shell.ExecCommand("brew", "search", pkg)
|
||||||
|
packages, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", h.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("brew", "upgrade", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) UpdateAllPackages() error {
|
||||||
|
cmd := shell.ExecCommand("brew", "upgrade")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HomebrewManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("brew", "list", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// homebrew_test.go
|
package packagemanager
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -17,13 +17,13 @@ func TestHomebrewManager_InstallManager(t *testing.T) {
|
||||||
hm := &HomebrewManager{}
|
hm := &HomebrewManager{}
|
||||||
|
|
||||||
// Mock exec.LookPath and executeShellCommand
|
// Mock exec.LookPath and executeShellCommand
|
||||||
execLookPath = func(file string) (string, error) {
|
shell.ExecLookPath = func(file string) (string, error) {
|
||||||
if file == "brew" {
|
if file == "brew" {
|
||||||
return "/usr/local/bin/brew", nil
|
return "/usr/local/bin/brew", nil
|
||||||
}
|
}
|
||||||
return "", exec.ErrNotFound
|
return "", exec.ErrNotFound
|
||||||
}
|
}
|
||||||
defer func() { execLookPath = exec.LookPath }()
|
defer func() { shell.ExecLookPath = exec.LookPath }()
|
||||||
|
|
||||||
if err := hm.InstallManager(); err != nil {
|
if err := hm.InstallManager(); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
|
@ -34,10 +34,10 @@ func TestHomebrewManager_InstallPackage(t *testing.T) {
|
||||||
hm := &HomebrewManager{}
|
hm := &HomebrewManager{}
|
||||||
|
|
||||||
// Mock exec.Command
|
// Mock exec.Command
|
||||||
execCommand = func(name string, arg ...string) *exec.Cmd {
|
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
|
||||||
return exec.Command("echo", "mocked brew install")
|
return exec.Command("echo", "mocked brew install")
|
||||||
}
|
}
|
||||||
defer func() { execCommand = exec.Command }()
|
defer func() { shell.ExecCommand = exec.Command }()
|
||||||
|
|
||||||
if err := hm.InstallPackage("test-package"); err != nil {
|
if err := hm.InstallPackage("test-package"); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
268
pkg/packagemanager/os.go
Normal file
268
pkg/packagemanager/os.go
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OSManager struct {
|
||||||
|
OS *OS
|
||||||
|
SudoPassword string
|
||||||
|
pm PackageManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOSManager(sudoPassword string) *OSManager {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
os, err := GetLinuxDistribution()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error getting os information: %v", err)
|
||||||
|
}
|
||||||
|
var pm PackageManager
|
||||||
|
switch os.ID {
|
||||||
|
case "debian", "ubuntu":
|
||||||
|
pm = &AptManager{SudoPassword: sudoPassword}
|
||||||
|
case "arch":
|
||||||
|
pm = &PacmanManager{SudoPassword: sudoPassword}
|
||||||
|
case "fedora":
|
||||||
|
pm = &DnfManager{SudoPassword: sudoPassword}
|
||||||
|
default:
|
||||||
|
log.Fatalf("Unsupported Linux distribution: %s", os.ID)
|
||||||
|
}
|
||||||
|
return &OSManager{
|
||||||
|
OS: os,
|
||||||
|
SudoPassword: sudoPassword,
|
||||||
|
pm: pm,
|
||||||
|
}
|
||||||
|
case "windows":
|
||||||
|
os, err := getPlatformInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := shell.ExecLookPath("winget"); err == nil {
|
||||||
|
return &OSManager{
|
||||||
|
OS: os,
|
||||||
|
SudoPassword: "",
|
||||||
|
pm: &WingetManager{},
|
||||||
|
}
|
||||||
|
} else if _, err := shell.ExecLookPath("choco"); err == nil {
|
||||||
|
return &OSManager{
|
||||||
|
OS: os,
|
||||||
|
SudoPassword: "",
|
||||||
|
pm: &ChocoManager{},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("Neither Winget nor Chocolatey found on Windows. Package management functionality will be limited.")
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
os, err := platformInfoMac()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err = shell.ExecLookPath("brew")
|
||||||
|
if err == nil {
|
||||||
|
return &OSManager{
|
||||||
|
OS: os,
|
||||||
|
SudoPassword: sudoPassword,
|
||||||
|
pm: &HomebrewManager{},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
manager := &HomebrewManager{}
|
||||||
|
manager.InstallManager()
|
||||||
|
return &OSManager{
|
||||||
|
OS: os,
|
||||||
|
SudoPassword: sudoPassword,
|
||||||
|
pm: manager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatal("Operating system not supported")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) Name() string {
|
||||||
|
return "OS Package Manager"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) InstallManager() error { return nil }
|
||||||
|
|
||||||
|
func (o *OSManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(o.pm, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) InstallPackage(pkg string) error {
|
||||||
|
return o.pm.InstallPackage(pkg) //(o.OS.InstallCommand, pkg, o.SudoPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) InstallBuildEssentials() error {
|
||||||
|
return InstallBuildEssentials(o.OS, o.SudoPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) RemovePackage(pkg string) error {
|
||||||
|
return o.pm.RemovePackage(pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) SearchPackage(pkg string) []string {
|
||||||
|
return o.pm.SearchPackage(pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) UpdatePackage(pkg string) error {
|
||||||
|
return o.pm.UpdatePackage(pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) UpdateAllPackages() error {
|
||||||
|
return o.pm.UpdateAllPackages()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OSManager) Check(pkg string) error {
|
||||||
|
return o.pm.Check(pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OS struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
PackageManager string
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOsRelease(osRelease string) *OS {
|
||||||
|
var result OS
|
||||||
|
result.ID = "Unknown"
|
||||||
|
result.Name = "Unknown"
|
||||||
|
result.Version = "Unknown"
|
||||||
|
|
||||||
|
lines := strings.Split(osRelease, "\n")
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
splitLine := strings.SplitN(line, "=", 2)
|
||||||
|
if len(splitLine) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch splitLine[0] {
|
||||||
|
case "ID":
|
||||||
|
result.ID = strings.ToLower(strings.Trim(splitLine[1], "\""))
|
||||||
|
case "NAME":
|
||||||
|
result.Name = strings.Trim(splitLine[1], "\"")
|
||||||
|
case "VERSION_ID":
|
||||||
|
result.Version = strings.Trim(splitLine[1], "\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := result.getPackageManager()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLinuxDistribution() (*OS, error) {
|
||||||
|
_, err := os.Stat("/etc/os-release")
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil, fmt.Errorf("unable to read system information")
|
||||||
|
}
|
||||||
|
|
||||||
|
osRelease, _ := os.ReadFile("/etc/os-release")
|
||||||
|
return parseOsRelease(string(osRelease)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstallBuildEssentials(os *OS, sudoPassword string) error {
|
||||||
|
var command string
|
||||||
|
switch os.PackageManager {
|
||||||
|
case "pacman":
|
||||||
|
command = "pacman -S --noconfirm --needed base-devel"
|
||||||
|
case "apt":
|
||||||
|
command = "apt install -y build-essential"
|
||||||
|
case "dnf":
|
||||||
|
command = "dnf install -y @development-tools"
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("keine Build Essentials für OS %s definiert", os.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Installiere Build Essentials für %s...\n", os.Name)
|
||||||
|
if err := InstallPackage(command, "", sudoPassword); err != nil {
|
||||||
|
return fmt.Errorf("error installing Build Essentials: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSysctlValue(key string) (string, error) {
|
||||||
|
stdout, err := shell.ExecCommand(".", "sysctl", key).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
version := strings.TrimPrefix(string(stdout), key+": ")
|
||||||
|
return strings.TrimSpace(version), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func platformInfoMac() (*OS, error) {
|
||||||
|
var result OS
|
||||||
|
result.ID = "Unknown"
|
||||||
|
result.Name = "MacOS"
|
||||||
|
result.Version = "Unknown"
|
||||||
|
|
||||||
|
version, err := getSysctlValue("kern.osproductversion")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.Version = version
|
||||||
|
ID, err := getSysctlValue("kern.osversion")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.ID = ID
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPlatformInfo() (*OS, error) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
return platformInfoWin()
|
||||||
|
case "darwin":
|
||||||
|
return platformInfoMac()
|
||||||
|
case "linux":
|
||||||
|
return GetLinuxDistribution()
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (os *OS) getPackageManager() error {
|
||||||
|
switch os.ID {
|
||||||
|
case "debian", "ubuntu":
|
||||||
|
os.PackageManager = "apt"
|
||||||
|
return nil
|
||||||
|
case "arch":
|
||||||
|
os.PackageManager = "pacman"
|
||||||
|
return nil
|
||||||
|
case "fedora":
|
||||||
|
os.PackageManager = "dnf"
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
pmcommands := []string{
|
||||||
|
"apt",
|
||||||
|
"dnf",
|
||||||
|
"pacman",
|
||||||
|
}
|
||||||
|
for _, pmname := range pmcommands {
|
||||||
|
_, err := shell.ExecLookPath(pmname)
|
||||||
|
if err == nil {
|
||||||
|
os.PackageManager = pmname
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("no packagemanager found fos os: %s", os.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,26 +1,20 @@
|
||||||
// osmanager_test.go
|
package packagemanager
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewOSManager(t *testing.T) {
|
func TestNewOSManager(t *testing.T) {
|
||||||
os := &OS{ID: "ubuntu", PackageManager: "apt"}
|
|
||||||
sudoPassword := "testpassword"
|
sudoPassword := "testpassword"
|
||||||
packages := []string{"git", "curl"}
|
|
||||||
|
|
||||||
manager := NewOSManager(os, sudoPassword, packages)
|
manager := NewOSManager(sudoPassword)
|
||||||
|
|
||||||
if manager.OS != os {
|
if manager.OS == nil {
|
||||||
t.Errorf("Expected OS to be %v, got %v", os, manager.OS)
|
t.Error("Expected OS to be non-nil")
|
||||||
}
|
}
|
||||||
if manager.SudoPassword != sudoPassword {
|
if manager.SudoPassword != sudoPassword {
|
||||||
t.Errorf("Expected SudoPassword to be %s, got %s", sudoPassword, manager.SudoPassword)
|
t.Errorf("Expected SudoPassword to be %s, got %s", sudoPassword, manager.SudoPassword)
|
||||||
}
|
}
|
||||||
if len(manager.Packages) != len(packages) {
|
|
||||||
t.Errorf("Expected Packages length to be %d, got %d", len(packages), len(manager.Packages))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOSManagerName(t *testing.T) {
|
func TestOSManagerName(t *testing.T) {
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package main
|
package packagemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -10,26 +12,17 @@ type Packages struct {
|
||||||
NonHeadless []string `mapstructure:"non_headless"`
|
NonHeadless []string `mapstructure:"non_headless"`
|
||||||
}
|
}
|
||||||
|
|
||||||
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 := execCommand("sudo", "-S", "sh", "-c", fullCmd)
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
command.Stdin = strings.NewReader(sudoPassword + "\n")
|
command.Stdin = strings.NewReader(sudoPassword + "\n")
|
||||||
output, err := command.CombinedOutput()
|
output, err := command.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(string(output), "not found") || strings.Contains(string(output), "no matching package") || strings.Contains(string(output), "Keine Übereinstimmung") || strings.Contains(string(output), "Ziel nicht gefunden") {
|
if strings.Contains(string(output), "not found") || strings.Contains(string(output), "no matching package") || strings.Contains(string(output), "Keine Übereinstimmung") || strings.Contains(string(output), "Ziel nicht gefunden") {
|
||||||
unavailablePackages = append(unavailablePackages, pkg)
|
log.Printf("Package %s not available\n", pkg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("failed to install %s: %v\n%s", pkg, err, string(output))
|
return fmt.Errorf("failed to install %s: %v\n%s", pkg, err, string(output))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printUnavailablePackages() {
|
|
||||||
if len(unavailablePackages) > 0 {
|
|
||||||
fmt.Println("\nFolgende Pakete waren nicht verfügbar:")
|
|
||||||
for _, pkg := range unavailablePackages {
|
|
||||||
fmt.Printf("- %s\n", pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
pkg/packagemanager/packagemanager.go
Normal file
13
pkg/packagemanager/packagemanager.go
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
type PackageManager interface {
|
||||||
|
Install(packages []string) error
|
||||||
|
Check(pkg string) error
|
||||||
|
InstallPackage(pkg string) error
|
||||||
|
InstallManager() error
|
||||||
|
RemovePackage(pkg string) error
|
||||||
|
SearchPackage(pkg string) []string
|
||||||
|
UpdatePackage(pkg string) error
|
||||||
|
UpdateAllPackages() error
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
81
pkg/packagemanager/pacman.go
Normal file
81
pkg/packagemanager/pacman.go
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PacmanManager struct {
|
||||||
|
SudoPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PacmanManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(m, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PacmanManager) Name() string {
|
||||||
|
return "OS Home Manager"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PacmanManager) InstallManager() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PacmanManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := "pacman -S --noconfirm --needed"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(m.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PacmanManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := "pacman -R"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(m.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacmanManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := "pacman -Ss"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(p.SudoPassword + "\n")
|
||||||
|
packages, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", p.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacmanManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := "pacman -S"
|
||||||
|
fullCmd := fmt.Sprintf("%s %s", cmd, pkg)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(p.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacmanManager) UpdateAllPackages() error {
|
||||||
|
cmd := "apt -S"
|
||||||
|
fullCmd := fmt.Sprintf("%s", cmd)
|
||||||
|
command := shell.ExecCommand("sudo", "-S", "sh", "-c", fullCmd)
|
||||||
|
command.Stdin = strings.NewReader(p.SudoPassword + "\n")
|
||||||
|
return command.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PacmanManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("paxman -Q | grep %s", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
66
pkg/packagemanager/pipx.go
Normal file
66
pkg/packagemanager/pipx.go
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PipxManager struct{}
|
||||||
|
|
||||||
|
func (p *PipxManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := InstallWithProgress(p, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) Name() string {
|
||||||
|
return "Pipx"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("brew"); err != nil {
|
||||||
|
installHomebrew()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := shell.ExecLookPath("pipx"); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := shell.ExecCommand("brew", "install", "pipx")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("pipx", "install", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("pipx", "uninstall", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) SearchPackage(pkg string) []string {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("pipx", "upgrade", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) UpdateAllPackages() error {
|
||||||
|
cmd := shell.ExecCommand("pipx", "upgrade-all")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PipxManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("/bin/sh", "-c", fmt.Sprintf("pipx list | grep %s", pkg))
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// pipx_test.go
|
package packagemanager
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -17,13 +17,13 @@ func TestPipxManager_InstallManager(t *testing.T) {
|
||||||
pm := &PipxManager{}
|
pm := &PipxManager{}
|
||||||
|
|
||||||
// Mock exec.LookPath
|
// Mock exec.LookPath
|
||||||
execLookPath = func(file string) (string, error) {
|
shell.ExecLookPath = func(file string) (string, error) {
|
||||||
if file == "pipx" {
|
if file == "pipx" {
|
||||||
return "/usr/bin/pipx", nil
|
return "/usr/bin/pipx", nil
|
||||||
}
|
}
|
||||||
return "", exec.ErrNotFound
|
return "", exec.ErrNotFound
|
||||||
}
|
}
|
||||||
defer func() { execLookPath = exec.LookPath }()
|
defer func() { shell.ExecLookPath = exec.LookPath }()
|
||||||
|
|
||||||
if err := pm.InstallManager(); err != nil {
|
if err := pm.InstallManager(); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
|
@ -34,10 +34,10 @@ func TestPipxManager_InstallPackage(t *testing.T) {
|
||||||
pm := &PipxManager{}
|
pm := &PipxManager{}
|
||||||
|
|
||||||
// Mock exec.Command
|
// Mock exec.Command
|
||||||
execCommand = func(name string, arg ...string) *exec.Cmd {
|
shell.ExecCommand = func(name string, arg ...string) *exec.Cmd {
|
||||||
return exec.Command("echo", "mocked pipx install")
|
return exec.Command("echo", "mocked pipx install")
|
||||||
}
|
}
|
||||||
defer func() { execCommand = exec.Command }()
|
defer func() { shell.ExecCommand = exec.Command }()
|
||||||
|
|
||||||
if err := pm.InstallPackage("test-package"); err != nil {
|
if err := pm.InstallPackage("test-package"); err != nil {
|
||||||
t.Errorf("Expected no error, got %v", err)
|
t.Errorf("Expected no error, got %v", err)
|
||||||
19
pkg/packagemanager/utils.go
Normal file
19
pkg/packagemanager/utils.go
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/schollz/progressbar/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InstallWithProgress(manager PackageManager, packages []string) error {
|
||||||
|
bar := progressbar.Default(int64(len(packages)), "Installiere "+manager.Name()+"-Pakete...")
|
||||||
|
for _, pkg := range packages {
|
||||||
|
err := manager.InstallPackage(pkg)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("\nError installing %s: %v\n", pkg, err)
|
||||||
|
}
|
||||||
|
bar.Add(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
30
pkg/packagemanager/win.go
Normal file
30
pkg/packagemanager/win.go
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func platformInfoWin() (*OS, error) {
|
||||||
|
var result OS
|
||||||
|
result.ID = "Unknown"
|
||||||
|
result.Name = "Windows"
|
||||||
|
result.Version = "Unknown"
|
||||||
|
|
||||||
|
key, _ := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||||
|
|
||||||
|
productName, _, _ := key.GetStringValue("ProductName")
|
||||||
|
currentBuild, _, _ := key.GetStringValue("CurrentBuildNumber")
|
||||||
|
displayVersion, _, _ := key.GetStringValue("DisplayVersion")
|
||||||
|
releaseId, _, _ := key.GetStringValue("ReleaseId")
|
||||||
|
|
||||||
|
result.Name = productName
|
||||||
|
result.Version = fmt.Sprintf("%s (Build: %s)", releaseId, currentBuild)
|
||||||
|
result.ID = displayVersion
|
||||||
|
|
||||||
|
return &result, key.Close()
|
||||||
|
}
|
||||||
8
pkg/packagemanager/win_dummy.go
Normal file
8
pkg/packagemanager/win_dummy.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
//go:build linux || darwin
|
||||||
|
// +build linux darwin
|
||||||
|
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
func platformInfoWin() (*OS, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
71
pkg/packagemanager/winget.go
Normal file
71
pkg/packagemanager/winget.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package packagemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"codeberg.org/Pata1704/system_setup_tool/internal/shell"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WingetManager struct{}
|
||||||
|
|
||||||
|
func (w *WingetManager) Install(packages []string) error {
|
||||||
|
if len(packages) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := InstallWithProgress(w, packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) Name() string {
|
||||||
|
return "Winget"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) InstallManager() error {
|
||||||
|
if _, err := shell.ExecLookPath("winget"); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return installHomebrew()
|
||||||
|
}
|
||||||
|
|
||||||
|
func installWinget() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) InstallPackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("winget", "install", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) RemovePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("winget", "uninstall", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) SearchPackage(pkg string) []string {
|
||||||
|
cmd := shell.ExecCommand("winget", "search", pkg)
|
||||||
|
packages, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching %s packages: %v", w.Name(), err)
|
||||||
|
}
|
||||||
|
packageList := strings.Split(strings.TrimSpace(string(packages)), "\n")
|
||||||
|
return packageList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) UpdatePackage(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("winget", "update", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) UpdateAllPackages() error {
|
||||||
|
cmd := shell.ExecCommand("winget", "update")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WingetManager) Check(pkg string) error {
|
||||||
|
cmd := shell.ExecCommand("wiget", "show", pkg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
3
renovate.json
Normal file
3
renovate.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||||
|
}
|
||||||
146
tui.go
146
tui.go
|
|
@ -1,146 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
currentPkgNameStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("211"))
|
|
||||||
doneStyle = lipgloss.NewStyle().Margin(1, 2)
|
|
||||||
checkMark = lipgloss.NewStyle().Foreground(lipgloss.Color("42")).SetString("✓")
|
|
||||||
unavailablePackages []string
|
|
||||||
)
|
|
||||||
|
|
||||||
type installedPkgMsg string
|
|
||||||
|
|
||||||
func run(cmd *cobra.Command, args []string) {
|
|
||||||
os, err := getLinuxDistribution()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sudoPassword, err := getSudoPassword()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var cfg Config
|
|
||||||
if err := viper.Unmarshal(&cfg); err != nil {
|
|
||||||
log.Fatalf("Fehler beim Lesen der Konfiguration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewConfirm().
|
|
||||||
Title("Möchten Sie eine headless Installation durchführen?").
|
|
||||||
Value(&cfg.Headless),
|
|
||||||
),
|
|
||||||
).WithTheme(huh.ThemeCatppuccin())
|
|
||||||
|
|
||||||
if err := form.Run(); err != nil {
|
|
||||||
log.Fatalf("Fehler bei der Benutzerabfrage: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unavailablePackages = []string{}
|
|
||||||
osManager := NewOSManager(os, sudoPassword, cfg.Packages.Headless)
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
var installBuild bool
|
|
||||||
form = huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewConfirm().
|
|
||||||
Title("Möchten Sie die Build Essentials installieren?").
|
|
||||||
Value(&installBuild),
|
|
||||||
),
|
|
||||||
).WithTheme(huh.ThemeCatppuccin())
|
|
||||||
|
|
||||||
err = form.Run()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if installBuild {
|
|
||||||
if err := osManager.InstallBuildEssentials(); err != nil {
|
|
||||||
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 {
|
|
||||||
if err := osManager.InstallSpecialSoftware(); err != nil {
|
|
||||||
log.Printf("Warnung bei der Installation spezieller Software: %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 := manager.Install(config.Packages); err != nil {
|
|
||||||
log.Printf("Warnung bei %s-Paketen: %v", manager.Name(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cfg.Dotfiles.Enable {
|
|
||||||
fmt.Println("\nKonfiguriere Dotfiles...")
|
|
||||||
if err := setupDotfiles(cfg.Dotfiles); err != nil {
|
|
||||||
log.Printf("Warnung bei Dotfiles-Setup: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
64
utils.go
64
utils.go
|
|
@ -1,64 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
"github.com/schollz/progressbar/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
execCommand = exec.Command
|
|
||||||
execLookPath = exec.LookPath
|
|
||||||
)
|
|
||||||
|
|
||||||
func getSudoPassword() (string, error) {
|
|
||||||
var password string
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewInput().
|
|
||||||
Title("Bitte geben Sie Ihr sudo-Passwort ein").
|
|
||||||
EchoMode(huh.EchoModePassword).
|
|
||||||
Value(&password),
|
|
||||||
),
|
|
||||||
).WithTheme(huh.ThemeCatppuccin())
|
|
||||||
|
|
||||||
err := form.Run()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("fehler bei der Passwortabfrage: %v", err)
|
|
||||||
}
|
|
||||||
return password, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a, b int) int {
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeShellCommand(command string, env string) error {
|
|
||||||
cmd := execCommand("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
|
|
||||||
}
|
|
||||||
|
|
||||||
func installWithProgress(manager PackageManager, packages []string) error {
|
|
||||||
bar := progressbar.Default(int64(len(packages)), "Installiere "+manager.Name()+"-Pakete...")
|
|
||||||
for _, pkg := range packages {
|
|
||||||
err := manager.InstallPackage(pkg)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("\nError installing %s: %v\n", pkg, err)
|
|
||||||
}
|
|
||||||
bar.Add(1)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os/exec"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMax(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
a, b, want int
|
|
||||||
}{
|
|
||||||
{1, 2, 2},
|
|
||||||
{5, 3, 5},
|
|
||||||
{0, 0, 0},
|
|
||||||
{-1, -5, -1},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := max(tt.a, tt.b)
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("max(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExecuteShellCommand(t *testing.T) {
|
|
||||||
// Mock execCommand
|
|
||||||
oldExecCommand := execCommand
|
|
||||||
defer func() { execCommand = oldExecCommand }()
|
|
||||||
|
|
||||||
execCommand = func(command string, args ...string) *exec.Cmd {
|
|
||||||
return exec.Command("echo", "mocked command")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := executeShellCommand("test command", "TEST_ENV=value")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("executeShellCommand() error = %v; want nil", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInstallWithProgress(t *testing.T) {
|
|
||||||
mockManager := &MockPackageManager{
|
|
||||||
packages: []string{"pkg1", "pkg2"},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := installWithProgress(mockManager, mockManager.packages)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("installWithProgress() error = %v; want nil", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mockManager.installedPackages) != len(mockManager.packages) {
|
|
||||||
t.Errorf("installWithProgress() installed %d packages; want %d", len(mockManager.installedPackages), len(mockManager.packages))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockPackageManager implementiert das PackageManager Interface für Tests
|
|
||||||
type MockPackageManager struct {
|
|
||||||
packages []string
|
|
||||||
installedPackages []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockPackageManager) Install(packages []string) error {
|
|
||||||
m.installedPackages = append(m.installedPackages, packages...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockPackageManager) InstallPackage(pkg string) error {
|
|
||||||
m.installedPackages = append(m.installedPackages, pkg)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockPackageManager) InstallManager() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockPackageManager) Name() string {
|
|
||||||
return "MockManager"
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue