package config import ( "context" "fmt" "os" "os/exec" "time" "git.dotya.ml/mirre-mt/pcmt/slogging" "github.com/philandstuff/dhall-golang/v6" "golang.org/x/exp/slog" ) type session struct { CookieName string CookieSecret string } type Config struct { Host string Port int AppName string LiveMode bool DevelMode bool Session session Registration struct{ Allowed bool } Logger struct { Json bool //nolint:revive Fmt string } } var log slogging.Slogger func LoadConfig(conf string, isPath bool) (*Config, error) { var config Config var err error slogger := slogging.Logger() // initialise if not already initialised. if slogger == nil { slogger = slogging.Init(true) } // have a local copy. log = *slogger // add attr to all statements made with the local copy. log.Logger = log.Logger.With( slog.Group("pcmt extra", slog.String("module", "config")), ) switch { case isPath: log.Debug("config from file") err = dhall.UnmarshalFile(conf, &config) case !isPath: log.Debug("config raw from cmdline") err = dhall.Unmarshal([]byte(conf), &config) } if !config.Logger.Json { slogger = slogging.Init(false) log.Logger = slogger.Logger.With( slog.Group("pcmt extra", slog.String("module", "config")), ) } if config.DevelMode && os.Getenv("PCMT_DEVEL") != "False" { log.Debug("set DEBUG level based on config value") slogger = slogging.SetLevel(slogging.LevelDebug) log.Logger = slogger.Logger.With( slog.Group("pcmt extra", slog.String("module", "config")), ) log.Debugf("parsed config: %+v", config) if dhallCmdExists() { _ = prettyPrintConfig(conf, isPath) } } // only return now, one we had a chance to print the loaded config (as // would be the case if the config adhered to the schema but our type // definition above didn't - "don't know how to decode into ...") if err != nil { return nil, err } return &config, nil } func prettyPrintConfig(conf string, isPath bool) error { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var cmd *exec.Cmd if isPath { cmd = exec.CommandContext(ctx, "/bin/sh", "-c", "dhall --file "+conf) //nolint:gosec } else { cmd = exec.CommandContext(ctx, "/bin/sh", "-c", "dhall <<< \""+conf+"\"") //nolint:gosec } output, err := cmd.CombinedOutput() if err != nil { log.Debug("could not pretty-print config", "error", err) return err } if isPath { fmt.Fprintln(os.Stderr, "\n"+conf+":\n"+string(output)) } else { fmt.Fprintln(os.Stderr, "\nconfig:\n"+string(output)) } return nil } func dhallCmdExists() bool { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() if err := exec.CommandContext(ctx, "/bin/sh", "-c", "command -v dhall").Run(); err != nil { log.Debug("no command dhall") return false } return true }