128 lines
3.6 KiB
Go
128 lines
3.6 KiB
Go
// Package settings holds user preferences for the print helper.
|
|
//
|
|
// Lookup order (first hit wins per field):
|
|
// 1. env VERAE_OPEN_ON_COMPLETE
|
|
// 2. user file ~/.verae/config.json (written by the installers for the console/logged-in user)
|
|
// 3. machine file %ProgramData%\Verae\PrintStamp\config.json (Windows)
|
|
// or /Library/Application Support/Verae/PrintStamp/config.json (macOS)
|
|
// 4. defaults (OpenOnComplete = "folder", LogLevel = info)
|
|
package settings
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// OpenOnComplete values.
|
|
const (
|
|
OpenFolder = "folder" // reveal the certificate PDF in Explorer/Finder
|
|
OpenPDF = "pdf" // open the certificate PDF in the default viewer
|
|
OpenNone = "none"
|
|
)
|
|
|
|
// Settings is the on-disk JSON shape.
|
|
type Settings struct {
|
|
OpenOnComplete string `json:"openOnComplete,omitempty"`
|
|
// LogLevel "debug" enables verbose helper logs (same as VERAE_LOG_LEVEL=debug).
|
|
LogLevel string `json:"logLevel,omitempty"`
|
|
}
|
|
|
|
// Default settings.
|
|
var Default = Settings{OpenOnComplete: OpenFolder}
|
|
|
|
// NormalizeOpen maps user input to a valid value ("" if invalid).
|
|
func NormalizeOpen(v string) string {
|
|
switch strings.ToLower(strings.TrimSpace(v)) {
|
|
case "folder", "reveal", "finder", "explorer", "show":
|
|
return OpenFolder
|
|
case "pdf", "open", "file":
|
|
return OpenPDF
|
|
case "none", "off", "no", "false", "0":
|
|
return OpenNone
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// UserPath is ~/.verae/config.json for the given home ("" = current user).
|
|
func UserPath(home string) string {
|
|
if home == "" {
|
|
home, _ = os.UserHomeDir()
|
|
}
|
|
return filepath.Join(home, ".verae", "config.json")
|
|
}
|
|
|
|
// MachinePath is the all-users default file.
|
|
func MachinePath() string {
|
|
if runtime.GOOS == "windows" {
|
|
pd := os.Getenv("ProgramData")
|
|
if pd == "" {
|
|
pd = `C:\ProgramData`
|
|
}
|
|
return filepath.Join(pd, "Verae", "PrintStamp", "config.json")
|
|
}
|
|
return "/Library/Application Support/Verae/PrintStamp/config.json"
|
|
}
|
|
|
|
func readFile(p string) (Settings, bool) {
|
|
var s Settings
|
|
b, err := os.ReadFile(p)
|
|
if err != nil {
|
|
return s, false
|
|
}
|
|
b = []byte(strings.TrimPrefix(string(b), "\uFEFF"))
|
|
if json.Unmarshal(b, &s) != nil {
|
|
return Settings{}, false
|
|
}
|
|
return s, true
|
|
}
|
|
|
|
// Load resolves the effective settings and a short description of where each came from.
|
|
func Load() (Settings, string) {
|
|
eff := Default
|
|
src := "default"
|
|
if s, ok := readFile(MachinePath()); ok {
|
|
if v := NormalizeOpen(s.OpenOnComplete); v != "" {
|
|
eff.OpenOnComplete, src = v, MachinePath()
|
|
}
|
|
}
|
|
if s, ok := readFile(UserPath("")); ok {
|
|
if v := NormalizeOpen(s.OpenOnComplete); v != "" {
|
|
eff.OpenOnComplete, src = v, UserPath("")
|
|
}
|
|
}
|
|
for _, p := range []string{MachinePath(), UserPath("")} {
|
|
if s, ok := readFile(p); ok && s.LogLevel != "" {
|
|
eff.LogLevel = strings.ToLower(strings.TrimSpace(s.LogLevel))
|
|
}
|
|
}
|
|
if v := NormalizeOpen(os.Getenv("VERAE_OPEN_ON_COMPLETE")); v != "" {
|
|
eff.OpenOnComplete, src = v, "env VERAE_OPEN_ON_COMPLETE"
|
|
}
|
|
return eff, src
|
|
}
|
|
|
|
// SetOpenOnComplete updates (merges) the JSON file at path, preserving unknown keys.
|
|
func SetOpenOnComplete(path, value string) error {
|
|
v := NormalizeOpen(value)
|
|
if v == "" {
|
|
return fmt.Errorf("openOnComplete must be folder, pdf or none (got %q)", value)
|
|
}
|
|
m := map[string]any{}
|
|
if b, err := os.ReadFile(path); err == nil {
|
|
_ = json.Unmarshal([]byte(strings.TrimPrefix(string(b), "\uFEFF")), &m)
|
|
}
|
|
m["openOnComplete"] = v
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
|
return err
|
|
}
|
|
b, _ := json.MarshalIndent(m, "", " ")
|
|
tmp := path + ".tmp"
|
|
if err := os.WriteFile(tmp, append(b, '\n'), 0o600); err != nil {
|
|
return err
|
|
}
|
|
return os.Rename(tmp, path)
|
|
}
|