Files
jbergner fe32431d21
Some checks failed
release-tag / release-image (push) Failing after 55s
init
2026-08-01 23:54:45 +02:00

94 lines
2.8 KiB
Go

package app
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// ResolveConfigPath determines which controller configuration file to load.
// Explicit CLI and environment paths are authoritative. Without either, the
// current directory, executable directory, and container default are checked.
func ResolveConfigPath(cliPath, envPath string) (string, error) {
if path := strings.TrimSpace(cliPath); path != "" {
return requireConfigFile(path, "-config")
}
if path := strings.TrimSpace(envPath); path != "" {
return requireConfigFile(path, "ENV_CONTROLLER_CONFIG")
}
candidates := make([]string, 0, 3)
if cwd, err := os.Getwd(); err == nil {
candidates = append(candidates, filepath.Join(cwd, "controller.json"))
}
if executable, err := os.Executable(); err == nil {
candidates = append(candidates, filepath.Join(filepath.Dir(executable), "controller.json"))
}
candidates = append(candidates, filepath.FromSlash("/config/controller.json"))
candidates = uniqueCleanPaths(candidates)
for _, candidate := range candidates {
info, err := os.Stat(candidate)
if err == nil && !info.IsDir() {
absolute, absErr := filepath.Abs(candidate)
if absErr == nil {
return absolute, nil
}
return candidate, nil
}
}
exampleHints := make([]string, 0, 2)
for _, candidate := range candidates {
example := filepath.Join(filepath.Dir(candidate), "controller.example.json")
if info, err := os.Stat(example); err == nil && !info.IsDir() {
exampleHints = append(exampleHints, example)
}
}
message := fmt.Sprintf("controller configuration not found; searched: %s", strings.Join(candidates, ", "))
if len(exampleHints) > 0 {
message += fmt.Sprintf("; create controller.json from: %s", strings.Join(uniqueCleanPaths(exampleHints), ", "))
}
message += "; alternatively pass -config <path> or set ENV_CONTROLLER_CONFIG"
return "", fmt.Errorf("%s", message)
}
func requireConfigFile(path, source string) (string, error) {
cleaned := filepath.Clean(path)
info, err := os.Stat(cleaned)
if err != nil {
return "", fmt.Errorf("configuration path from %s %q: %w", source, cleaned, err)
}
if info.IsDir() {
return "", fmt.Errorf("configuration path from %s %q is a directory", source, cleaned)
}
absolute, err := filepath.Abs(cleaned)
if err == nil {
return absolute, nil
}
return cleaned, nil
}
func uniqueCleanPaths(paths []string) []string {
seen := make(map[string]struct{}, len(paths))
result := make([]string, 0, len(paths))
for _, path := range paths {
if strings.TrimSpace(path) == "" {
continue
}
cleaned := filepath.Clean(path)
key := cleaned
if filepath.Separator == '\\' {
key = strings.ToLower(cleaned)
}
if _, exists := seen[key]; exists {
continue
}
seen[key] = struct{}{}
result = append(result, cleaned)
}
return result
}