repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

Eric Bower  ·  2025-03-28

cfg.go

  1package git
  2
  3import (
  4	"fmt"
  5	"log/slog"
  6	"path/filepath"
  7	"strings"
  8	"time"
  9
 10	"github.com/charmbracelet/ssh"
 11	"github.com/knadh/koanf/parsers/toml"
 12	"github.com/knadh/koanf/providers/env"
 13	"github.com/knadh/koanf/providers/file"
 14	"github.com/knadh/koanf/v2"
 15)
 16
 17var k = koanf.New(".")
 18
 19type GitCfg struct {
 20	DataDir    string          `koanf:"data_dir"`
 21	Url        string          `koanf:"url"`
 22	Host       string          `koanf:"host"`
 23	SshPort    string          `koanf:"ssh_port"`
 24	WebPort    string          `koanf:"web_port"`
 25	AdminsStr  []string        `koanf:"admins"`
 26	Admins     []ssh.PublicKey `koanf:"admins_pk"`
 27	CreateRepo string          `koanf:"create_repo"`
 28	Theme      string          `koanf:"theme"`
 29	TimeFormat string          `koanf:"time_format"`
 30	Desc       string          `koanf:"desc"`
 31	Logger     *slog.Logger
 32}
 33
 34func LoadConfigFile(fpath string, logger *slog.Logger) {
 35	fpp, err := filepath.Abs(fpath)
 36	if err != nil {
 37		panic(err)
 38	}
 39	logger.Info("loading configuration file", "fpath", fpp)
 40
 41	if err := k.Load(file.Provider(fpp), toml.Parser()); err != nil {
 42		panic(fmt.Sprintf("error loading config: %v", err))
 43	}
 44}
 45
 46func NewGitCfg(logger *slog.Logger) *GitCfg {
 47	err := k.Load(env.Provider("GITPR_", ".", func(s string) string {
 48		keyword := strings.ToLower(strings.TrimPrefix(s, "GITPR_"))
 49		return keyword
 50	}), nil)
 51	if err != nil {
 52		panic(fmt.Sprintf("could not load environment variables: %v", err))
 53	}
 54
 55	var out GitCfg
 56	err = k.UnmarshalWithConf("", &out, koanf.UnmarshalConf{Tag: "koanf"})
 57	if err != nil {
 58		panic(fmt.Sprintf("could not unmarshal config: %v", err))
 59	}
 60
 61	if len(out.AdminsStr) > 0 {
 62		keys, err := GetAuthorizedKeys(out.AdminsStr)
 63		if err == nil {
 64			out.Admins = keys
 65		} else {
 66			panic(fmt.Sprintf("could not parse authorized keys file: %v", err))
 67		}
 68	} else {
 69		logger.Info("no admin specified in config so no one can submit a review!")
 70	}
 71
 72	// make datadir absolute
 73	tmpdir := out.DataDir
 74	if out.DataDir == "" {
 75		tmpdir = "./data"
 76	}
 77	datadir, err := filepath.Abs(tmpdir)
 78	out.DataDir = datadir
 79	if err != nil {
 80		panic(err)
 81	}
 82
 83	if out.Host == "" {
 84		out.Host = "0.0.0.0"
 85	}
 86
 87	if out.SshPort == "" {
 88		out.SshPort = "2222"
 89	}
 90
 91	if out.WebPort == "" {
 92		out.WebPort = "3000"
 93	}
 94
 95	if out.Theme == "" {
 96		out.Theme = "dracula"
 97	}
 98
 99	if out.TimeFormat == "" {
100		out.TimeFormat = time.RFC3339
101	}
102
103	if out.CreateRepo == "" {
104		out.CreateRepo = "admin"
105	}
106
107	logger.Info(
108		"config",
109		"url", out.Url,
110		"data_dir", out.DataDir,
111		"host", out.Host,
112		"ssh_port", out.SshPort,
113		"web_port", out.WebPort,
114		"theme", out.Theme,
115		"time_format", out.TimeFormat,
116		"create_repo", out.CreateRepo,
117		"desc", out.Desc,
118	)
119
120	for _, pubkey := range out.AdminsStr {
121		logger.Info("admin", "pubkey", pubkey)
122	}
123
124	out.Logger = logger
125	return &out
126}