internal/config/config.go
1
// Package config lets every flag be set from the environment, which is how a
2
// container is configured.
3
package config
5
import (
6
"flag"
7
"fmt"
8
"os"
9
"strings"
10
)
12
const Prefix = "KOMENT_"
14
// EnvName is the variable that stands in for a flag: --streamable-http becomes
15
// KOMENT_STREAMABLE_HTTP.
16
func EnvName(flagName string) string {
17
return Prefix + strings.ToUpper(strings.ReplaceAll(flagName, "-", "_"))
18
}
20
// FromEnvironment fills in any flag the caller did not pass. An explicit flag
21
// always wins, so a container's environment sets the default and a person
22
// debugging it can still override on the command line.
23
//
24
// It runs after Parse because that is the only point at which "was this flag
25
// actually given" is knowable.
26
func FromEnvironment(flags *flag.FlagSet) error {
27
given := map[string]bool{}
28
flags.Visit(func(f *flag.Flag) { given[f.Name] = true })
30
var failed error
31
flags.VisitAll(func(f *flag.Flag) {
32
if given[f.Name] || failed != nil {
33
return
34
}
35
value, ok := os.LookupEnv(EnvName(f.Name))
36
if !ok {
37
return
38
}
39
if err := f.Value.Set(value); err != nil {
40
failed = fmt.Errorf("%s=%q is not valid for --%s: %w", EnvName(f.Name), value, f.Name, err)
41
}
42
})
43
return failed
44
}
46
// Usage renders the environment variable for each flag, so --help documents
47
// both ways of setting it rather than only one.
48
func Usage(flags *flag.FlagSet) string {
49
var out strings.Builder
50
flags.VisitAll(func(f *flag.Flag) {
51
fmt.Fprintf(&out, " --%-18s %-24s %s\n", f.Name, EnvName(f.Name), f.Usage)
52
})
53
return out.String()
54
}
56
// Root is the repository koment serves. It exists for containers, where the
57
// working directory is a mount point rather than somewhere a person cd'd to.
58
func Root() (string, bool) {
59
root, ok := os.LookupEnv(Prefix + "REPO")
60
return root, ok && root != ""
61
}