hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/internal/setup/setup.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/setup/setup.go')
-rw-r--r--internal/setup/setup.go84
1 files changed, 74 insertions, 10 deletions
diff --git a/internal/setup/setup.go b/internal/setup/setup.go
index eafaaa0..c2f8c10 100644
--- a/internal/setup/setup.go
+++ b/internal/setup/setup.go
@@ -12,10 +12,9 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/hachem-wtf/benson/internal/config"
+ "github.com/hachem-wtf/benson/internal/fabric"
)
-// Run is the server-manager wizard. It configures Minecraft/Fabric versions,
-// paths, merge hooks and mods — everything except the Discord bot.
func Run() error {
cfg := loadConfig()
@@ -32,6 +31,8 @@ func Run() error {
confirm = true
)
+ games, loaders, installers := fetchFabricVersions()
+
form := huh.NewForm(
huh.NewGroup(
huh.NewNote().
@@ -39,12 +40,16 @@ func Run() error {
Description("Configure the server manager.\nThe Discord bot is optional — run `benson setup bot` for that."),
),
huh.NewGroup(
- huh.NewInput().Title("Minecraft version").Placeholder("1.21.10").Value(&mcVersion).Validate(required("Minecraft version")),
- huh.NewInput().Title("Fabric loader version").Placeholder("0.17.3").Value(&fabricLoader).Validate(required("Fabric loader version")),
- huh.NewInput().Title("Loader / installer version").Placeholder("1.1.0").Value(&loaderMeta).Validate(required("loader version")),
- huh.NewInput().Title("Java path").Description("Leave blank to use 'java' from PATH").Value(&javaPath),
- ).Title("Minecraft / Fabric"),
+ versionField("Minecraft version", "The Minecraft release your server runs — newest stable is recommended", games, &mcVersion, "1.21.10"),
+ ),
+ huh.NewGroup(
+ versionField("Fabric loader version", "The Fabric mod loader that boots your mods — newest is recommended", loaders, &fabricLoader, "0.17.3"),
+ ),
+ huh.NewGroup(
+ versionField("Fabric installer version", "Builds the server jar from the loader — newest is recommended", installers, &loaderMeta, "1.1.0"),
+ ),
huh.NewGroup(
+ huh.NewInput().Title("Java path").Description("Leave blank to use 'java' from PATH").Value(&javaPath),
huh.NewInput().Title("Server location").Description("Live server directory, merged into by 'merge'").Value(&serverLoc),
huh.NewInput().Title("Backup location").Description("Where server backups are written").Value(&backupLoc),
huh.NewInput().Title("Pre-merge command").Description("Optional shell command run before merging").Value(&preCmd),
@@ -81,8 +86,6 @@ func Run() error {
return nil
}
-// RunBot is the Discord-bot wizard. It configures the bot token, channel and
-// check interval, leaving the server-manager settings untouched.
func RunBot() error {
cfg := loadConfig()
api := loadAPI()
@@ -136,6 +139,68 @@ func RunBot() error {
return nil
}
+func fetchFabricVersions() (games, loaders, installers []string) {
+ client := fabric.NewClient()
+
+ if gv, err := client.GameVersions(); err == nil {
+ for _, v := range gv {
+ if v.Stable {
+ games = append(games, v.Version)
+ }
+ }
+ }
+ if lv, err := client.LoaderVersions(); err == nil {
+ for _, v := range lv {
+ loaders = append(loaders, v.Version)
+ }
+ }
+ if iv, err := client.InstallerVersions(); err == nil {
+ for _, v := range iv {
+ installers = append(installers, v.Version)
+ }
+ }
+ return games, loaders, installers
+}
+
+func versionField(title, desc string, options []string, value *string, placeholder string) huh.Field {
+ if len(options) == 0 {
+ return huh.NewInput().
+ Title(title).
+ Placeholder(placeholder).
+ Value(value).
+ Validate(required(title))
+ }
+
+ *value = defaultOr(*value, options)
+ return huh.NewSelect[string]().
+ Title(title).
+ Description(desc).
+ Options(recommendedOptions(options)...).
+ Height(12).
+ Value(value)
+}
+
+func recommendedOptions(versions []string) []huh.Option[string] {
+ options := make([]huh.Option[string], len(versions))
+ for i, v := range versions {
+ label := v
+ if i == 0 {
+ label = v + " · recommended"
+ }
+ options[i] = huh.NewOption(label, v)
+ }
+ return options
+}
+
+func defaultOr(current string, options []string) string {
+ for _, o := range options {
+ if o == current {
+ return current
+ }
+ }
+ return options[0]
+}
+
func loadConfig() *config.Config {
if cfg, err := config.Load(); err == nil {
return cfg
@@ -150,7 +215,6 @@ func loadAPI() *config.API {
return &config.API{}
}
-// runForm runs a themed form, reporting whether the user confirmed the write.
func runForm(form *huh.Form) (bool, error) {
if err := form.WithTheme(emberTheme()).Run(); err != nil {
if errors.Is(err, huh.ErrUserAborted) {