// Package modcfg loads an app module's values from its local, untracked // apps/modules//module.yaml, with environment-variable overrides. // // Compiled-in module code is tracked in git and must contain no account ids, // policy keys, video ids, license URLs or origin hostnames. Those live here, in // a file git ignores, and can also be supplied by flag or environment so a run // needs no file at all. package modcfg import ( "fmt" "os" "path/filepath" "strings" "drmdecryption/repo" "gopkg.in/yaml.v3" ) // Dir returns the directory holding a module's local values. func Dir(name string) string { return filepath.Join(repo.Root(), "apps", "modules", name) } // Path returns the module's values file path. func Path(name string) string { return filepath.Join(Dir(name), "module.yaml") } // Result reports where a module's values came from, for `drm modules`. type Result struct { Path string Loaded bool } // Load reads apps/modules//module.yaml into dst. A missing file is not an // error — the module runs on its Go defaults plus flags/env. func Load(name string, dst any) (Result, error) { path := Path(name) res := Result{Path: path} b, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return res, nil } return res, err } if err := yaml.Unmarshal(b, dst); err != nil { return res, fmt.Errorf("%s: %w", path, err) } res.Loaded = true return res, nil } // EnvKey is the environment variable a field override is read from: // TG4_POLICY_KEY for module "tg4", field "policy_key". func EnvKey(module, field string) string { clean := func(s string) string { s = strings.ToUpper(s) s = strings.ReplaceAll(s, "-", "_") s = strings.ReplaceAll(s, ".", "_") return s } return clean(module) + "_" + clean(field) } // Env returns the environment override for a field, or "". func Env(module, field string) string { return strings.TrimSpace(os.Getenv(EnvKey(module, field))) } // Override picks the first non-empty of: flag value, environment, current value. // Use it in a module's config resolution so precedence is uniform. func Override(module, field, flagVal, current string) string { if strings.TrimSpace(flagVal) != "" { return flagVal } if v := Env(module, field); v != "" { return v } return current } // Resolve makes a module-relative path absolute against the repo root. func Resolve(p string) string { if p == "" || filepath.IsAbs(p) { return p } return filepath.Join(repo.Root(), p) }