cmd/weimar/root.go (view raw)
1package main
2
3import (
4 "errors"
5 "fmt"
6 "log/slog"
7 "os"
8 "strings"
9
10 "github.com/spf13/cobra"
11 "github.com/spf13/viper"
12)
13
14var cfgFile string
15
16var rootCmd = &cobra.Command{
17 Use: "weimar",
18 Short: "Self-hosted media repository for small groups",
19 Long: `weimar is a single-binary media repository for home servers.
20Store, tag, and browse memes and group-interest images with friends.`,
21 PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
22 return initConfig()
23 },
24 SilenceUsage: true,
25 SilenceErrors: true,
26}
27
28func Execute() error {
29 return rootCmd.Execute()
30}
31
32func init() {
33 rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "path to config file (default ./weimar.toml)")
34 rootCmd.PersistentFlags().String("log-level", "info", "log level (debug, info, warn, error)")
35 viper.BindPFlag("log-level", rootCmd.PersistentFlags().Lookup("log-level"))
36}
37
38func initConfig() error {
39 if cfgFile != "" {
40 viper.SetConfigFile(cfgFile)
41 } else {
42 viper.AddConfigPath(".")
43 viper.SetConfigName("weimar")
44 }
45
46 viper.SetEnvPrefix("WEIMAR")
47 viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
48 viper.AutomaticEnv()
49
50 if err := viper.ReadInConfig(); err != nil {
51 var notFound viper.ConfigFileNotFoundError
52 if errors.As(err, ¬Found) {
53 // No config file is fine — use defaults + env.
54 } else {
55 return fmt.Errorf("reading config: %w", err)
56 }
57 }
58
59 setDefaults()
60
61 level := slog.LevelInfo
62 switch strings.ToLower(viper.GetString("log-level")) {
63 case "debug":
64 level = slog.LevelDebug
65 case "warn":
66 level = slog.LevelWarn
67 case "error":
68 level = slog.LevelError
69 }
70 slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: level})))
71
72 return nil
73}
74
75func setDefaults() {
76 viper.SetDefault("server.host", "0.0.0.0")
77 viper.SetDefault("server.port", 8080)
78 viper.SetDefault("database.path", "./data/weimar.db")
79 viper.SetDefault("storage.path", "./data/images")
80 viper.SetDefault("upload.max_size_mb", 50)
81 viper.SetDefault("upload.rate_limit_per_minute", 0)
82 viper.SetDefault("auth.allow_registration", true)
83 viper.SetDefault("auth.require_auth_for_browse", false)
84}