files.go

 1package config
 2
 3import (
 4	"os"
 5	"path/filepath"
 6	"sort"
 7	"strings"
 8)
 9
10// DefaultConfigDirs lists the base directories searched for config files,
11// in ascending priority order.
12var DefaultConfigDirs = []string{
13	"/usr/share/keld",
14	"/etc/keld",
15	"~/.config/keld",
16}
17
18// DiscoverFiles returns config file paths in ascending priority order.
19//
20// The search order is:
21//  1. For each directory in DefaultConfigDirs: config.toml, then sorted conf.d/*.toml
22//  2. Paths/globs from the KELD_CONFIG_PATHS env var (colon-separated)
23//  3. If KELD_CONFIG_FILE is set, it replaces ALL of the above
24//
25// All paths support ~ (home dir) and $VAR expansion.
26func DiscoverFiles() []string {
27	return discoverFiles(os.Getenv)
28}
29
30// discoverFiles is the testable core; getenv abstracts os.Getenv.
31func discoverFiles(getenv func(string) string) []string {
32	if single := getenv("KELD_CONFIG_FILE"); single != "" {
33		return []string{ExpandPath(single)}
34	}
35
36	var paths []string
37
38	for _, dir := range DefaultConfigDirs {
39		dir = ExpandPath(dir)
40
41		paths = append(paths, filepath.Join(dir, "config.toml"))
42		paths = append(paths, sortedGlob(filepath.Join(dir, "conf.d", "*.toml"))...)
43	}
44
45	if extra := getenv("KELD_CONFIG_PATHS"); extra != "" {
46		for _, entry := range strings.Split(extra, ":") {
47			entry = ExpandPath(strings.TrimSpace(entry))
48			if strings.ContainsAny(entry, "*?[") {
49				paths = append(paths, sortedGlob(entry)...)
50			} else {
51				paths = append(paths, entry)
52			}
53		}
54	}
55
56	return paths
57}
58
59// ExpandPath expands ~ to the user's home directory and $VAR references.
60func ExpandPath(p string) string {
61	if strings.HasPrefix(p, "~/") || p == "~" {
62		home, err := os.UserHomeDir()
63		if err == nil {
64			p = home + p[1:]
65		}
66	}
67	return os.ExpandEnv(p)
68}
69
70// sortedGlob returns glob matches in sorted order, or nil on error.
71func sortedGlob(pattern string) []string {
72	matches, err := filepath.Glob(pattern)
73	if err != nil || len(matches) == 0 {
74		return nil
75	}
76	sort.Strings(matches)
77	return matches
78}