1package cli
2
3import (
4	"os"
5	"strings"
6
7	"github.com/traefik/paerser/cli"
8	"github.com/traefik/paerser/file"
9	"github.com/traefik/paerser/flag"
10	"github.com/traefik/traefik/v2/pkg/log"
11)
12
13// FileLoader loads a configuration from a file.
14type FileLoader struct {
15	ConfigFileFlag string
16	filename       string
17}
18
19// GetFilename returns the configuration file if any.
20func (f *FileLoader) GetFilename() string {
21	return f.filename
22}
23
24// Load loads the command's configuration from a file either specified with the -traefik.configfile flag, or from default locations.
25func (f *FileLoader) Load(args []string, cmd *cli.Command) (bool, error) {
26	ref, err := flag.Parse(args, cmd.Configuration)
27	if err != nil {
28		_ = cmd.PrintHelp(os.Stdout)
29		return false, err
30	}
31
32	configFileFlag := "traefik.configfile"
33	if _, ok := ref["traefik.configFile"]; ok {
34		configFileFlag = "traefik.configFile"
35	}
36
37	if f.ConfigFileFlag != "" {
38		configFileFlag = "traefik." + f.ConfigFileFlag
39		if _, ok := ref[strings.ToLower(configFileFlag)]; ok {
40			configFileFlag = "traefik." + strings.ToLower(f.ConfigFileFlag)
41		}
42	}
43
44	configFile, err := loadConfigFiles(ref[configFileFlag], cmd.Configuration)
45	if err != nil {
46		return false, err
47	}
48
49	f.filename = configFile
50
51	if configFile == "" {
52		return false, nil
53	}
54
55	logger := log.WithoutContext()
56	logger.Printf("Configuration loaded from file: %s", configFile)
57
58	content, _ := os.ReadFile(configFile)
59	logger.Debug(string(content))
60
61	return true, nil
62}
63
64// loadConfigFiles tries to decode the given configuration file and all default locations for the configuration file.
65// It stops as soon as decoding one of them is successful.
66func loadConfigFiles(configFile string, element interface{}) (string, error) {
67	finder := cli.Finder{
68		BasePaths:  []string{"/etc/traefik/traefik", "$XDG_CONFIG_HOME/traefik", "$HOME/.config/traefik", "./traefik"},
69		Extensions: []string{"toml", "yaml", "yml"},
70	}
71
72	filePath, err := finder.Find(configFile)
73	if err != nil {
74		return "", err
75	}
76
77	if len(filePath) == 0 {
78		return "", nil
79	}
80
81	if err := file.Decode(filePath, element); err != nil {
82		return "", err
83	}
84	return filePath, nil
85}
86