Replace the legacy Go implementation as the production path, quarantine the reference tree, add deterministic release packaging and version metadata, and run verification through GitLab CI.
310 lines
9.3 KiB
Go
310 lines
9.3 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
type FocusBehaviour string
|
|
|
|
const (
|
|
FocusFirstNonCached FocusBehaviour = "default"
|
|
FocusNone FocusBehaviour = "no-focus"
|
|
FocusEnvironment FocusBehaviour = "environment"
|
|
FocusUsername FocusBehaviour = "username"
|
|
FocusPassword FocusBehaviour = "password"
|
|
)
|
|
|
|
type ShellLoginFlag string
|
|
|
|
const (
|
|
ShellLoginNone ShellLoginFlag = "none"
|
|
ShellLoginShort ShellLoginFlag = "short"
|
|
ShellLoginLong ShellLoginFlag = "long"
|
|
)
|
|
|
|
type BackgroundStyle struct {
|
|
Color string `toml:"color"`
|
|
ShowBorder bool `toml:"show_border"`
|
|
BorderColor string `toml:"border_color"`
|
|
}
|
|
|
|
type BackgroundConfig struct {
|
|
ShowBackground bool `toml:"show_background"`
|
|
Style BackgroundStyle `toml:"style"`
|
|
}
|
|
|
|
type PowerControl struct {
|
|
Hint string `toml:"hint"`
|
|
HintColor string `toml:"hint_color"`
|
|
HintModifiers string `toml:"hint_modifiers"`
|
|
Key string `toml:"key"`
|
|
Cmd string `toml:"cmd"`
|
|
}
|
|
|
|
type PowerControlConfig struct {
|
|
HintMargin uint16 `toml:"hint_margin"`
|
|
BaseEntries []PowerControl `toml:"base_entries"`
|
|
Entries []PowerControl `toml:"entries"`
|
|
}
|
|
|
|
type SwitcherConfig struct {
|
|
SwitcherVisibility string `toml:"switcher_visibility"`
|
|
ToggleHint string `toml:"toggle_hint"`
|
|
ToggleHintColor string `toml:"toggle_hint_color"`
|
|
ToggleHintModifiers string `toml:"toggle_hint_modifiers"`
|
|
IncludeTTYShell bool `toml:"include_tty_shell"`
|
|
Remember bool `toml:"remember"`
|
|
ShowMovers bool `toml:"show_movers"`
|
|
MoverColor string `toml:"mover_color"`
|
|
MoverColorFocused string `toml:"mover_color_focused"`
|
|
MoverModifiers string `toml:"mover_modifiers"`
|
|
MoverModifiersFocused string `toml:"mover_modifiers_focused"`
|
|
LeftMover string `toml:"left_mover"`
|
|
RightMover string `toml:"right_mover"`
|
|
MoverMargin uint16 `toml:"mover_margin"`
|
|
ShowNeighbours bool `toml:"show_neighbours"`
|
|
NeighbourColor string `toml:"neighbour_color"`
|
|
NeighbourColorFocused string `toml:"neighbour_color_focused"`
|
|
NeighbourModifiers string `toml:"neighbour_modifiers"`
|
|
NeighbourModifiersFocused string `toml:"neighbour_modifiers_focused"`
|
|
NeighbourMargin uint16 `toml:"neighbour_margin"`
|
|
SelectedColor string `toml:"selected_color"`
|
|
SelectedColorFocused string `toml:"selected_color_focused"`
|
|
SelectedModifiers string `toml:"selected_modifiers"`
|
|
SelectedModifiersFocused string `toml:"selected_modifiers_focused"`
|
|
MaxDisplayLength uint16 `toml:"max_display_length"`
|
|
NoEnvsText string `toml:"no_envs_text"`
|
|
NoEnvsColor string `toml:"no_envs_color"`
|
|
NoEnvsColorFocused string `toml:"no_envs_color_focused"`
|
|
NoEnvsModifiers string `toml:"no_envs_modifiers"`
|
|
NoEnvsModifiersFocused string `toml:"no_envs_modifiers_focused"`
|
|
}
|
|
|
|
type InputFieldStyle struct {
|
|
ShowTitle bool `toml:"show_title"`
|
|
Title string `toml:"title"`
|
|
ShowBorder bool `toml:"show_border"`
|
|
TitleColor string `toml:"title_color"`
|
|
TitleColorFocused string `toml:"title_color_focused"`
|
|
ContentColor string `toml:"content_color"`
|
|
ContentColorFocused string `toml:"content_color_focused"`
|
|
BorderColor string `toml:"border_color"`
|
|
BorderColorFocused string `toml:"border_color_focused"`
|
|
UseMaxWidth bool `toml:"use_max_width"`
|
|
MaxWidth uint16 `toml:"max_width"`
|
|
}
|
|
|
|
type UsernameFieldConfig struct {
|
|
Remember bool `toml:"remember"`
|
|
Style InputFieldStyle `toml:"style"`
|
|
}
|
|
|
|
type PasswordFieldConfig struct {
|
|
ReplacementChar string `toml:"content_replacement_character"`
|
|
Style InputFieldStyle `toml:"style"`
|
|
}
|
|
|
|
type X11Config struct {
|
|
Display string `toml:"x11_display"`
|
|
ServerTimeoutSecs uint16 `toml:"xserver_timeout_secs"`
|
|
ServerLogPath string `toml:"xserver_log_path"`
|
|
ServerPath string `toml:"xserver_path"`
|
|
XauthPath string `toml:"xauth_path"`
|
|
ScriptsPath string `toml:"scripts_path"`
|
|
SetupPath string `toml:"xsetup_path"`
|
|
SessionsPath string `toml:"xsessions_path"`
|
|
}
|
|
|
|
type WaylandConfig struct {
|
|
ScriptsPath string `toml:"scripts_path"`
|
|
SessionsPath string `toml:"wayland_sessions_path"`
|
|
}
|
|
|
|
type Config struct {
|
|
TTY uint8 `toml:"tty"`
|
|
MainLogPath string `toml:"main_log_path"`
|
|
ClientLogPath string `toml:"client_log_path"`
|
|
CachePath string `toml:"cache_path"`
|
|
DoLog bool `toml:"do_log"`
|
|
PAMService string `toml:"pam_service"`
|
|
SystemShell string `toml:"system_shell"`
|
|
InitialPath string `toml:"initial_path"`
|
|
ShellLoginFlag ShellLoginFlag `toml:"shell_login_flag"`
|
|
FocusBehaviour FocusBehaviour `toml:"focus_behaviour"`
|
|
Background BackgroundConfig `toml:"background"`
|
|
PowerControls PowerControlConfig `toml:"power_controls"`
|
|
Switcher SwitcherConfig `toml:"environment_switcher"`
|
|
Username UsernameFieldConfig `toml:"username_field"`
|
|
Password PasswordFieldConfig `toml:"password_field"`
|
|
X11 X11Config `toml:"x11"`
|
|
Wayland WaylandConfig `toml:"wayland"`
|
|
}
|
|
|
|
func Default() Config {
|
|
var c Config
|
|
if err := toml.Unmarshal([]byte(defaultTOML), &c); err != nil {
|
|
panic("default config: " + err.Error())
|
|
}
|
|
return c
|
|
}
|
|
|
|
func LoadPartial(filename string, vars map[string]string, dst *Config) error {
|
|
raw, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
return fmt.Errorf("read %s: %w", filename, err)
|
|
}
|
|
if vars != nil {
|
|
raw = []byte(resolveVars(string(raw), vars))
|
|
}
|
|
return toml.Unmarshal(raw, dst)
|
|
}
|
|
|
|
func LoadVariables(filename string) (map[string]string, error) {
|
|
raw, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read %s: %w", filename, err)
|
|
}
|
|
// Parse a flat TOML table of string values.
|
|
vars := make(map[string]string)
|
|
var table map[string]any
|
|
if err := toml.Unmarshal(raw, &table); err != nil {
|
|
return nil, fmt.Errorf("parse %s: %w", filename, err)
|
|
}
|
|
for k, v := range table {
|
|
vars[k] = fmt.Sprint(v)
|
|
}
|
|
return vars, nil
|
|
}
|
|
|
|
// ── variable substitution ───────────────────────────────────────────────
|
|
|
|
func resolveVars(in string, vars map[string]string) string {
|
|
for k, v := range vars {
|
|
in = strings.ReplaceAll(in, "$"+k, v)
|
|
}
|
|
return in
|
|
}
|
|
|
|
// ── embedded default config ─────────────────────────────────────────────
|
|
|
|
const defaultTOML = `
|
|
tty = 2
|
|
main_log_path = "/var/log/latchd.log"
|
|
client_log_path = "/var/log/latchd.client.log"
|
|
cache_path = "/var/cache/latchd"
|
|
do_log = true
|
|
pam_service = "latchd"
|
|
system_shell = "/bin/sh"
|
|
initial_path = "/usr/local/sbin:/usr/local/bin:/usr/bin"
|
|
shell_login_flag = "short"
|
|
focus_behaviour = "default"
|
|
|
|
[background]
|
|
show_background = true
|
|
|
|
[background.style]
|
|
color = "black"
|
|
show_border = true
|
|
border_color = "white"
|
|
|
|
[power_controls]
|
|
hint_margin = 2
|
|
entries = []
|
|
|
|
[[power_controls.base_entries]]
|
|
hint = "Shutdown"
|
|
hint_color = "dark gray"
|
|
hint_modifiers = ""
|
|
key = "F1"
|
|
cmd = "systemctl poweroff -l"
|
|
|
|
[[power_controls.base_entries]]
|
|
hint = "Reboot"
|
|
hint_color = "dark gray"
|
|
hint_modifiers = ""
|
|
key = "F2"
|
|
cmd = "systemctl reboot -l"
|
|
|
|
[environment_switcher]
|
|
switcher_visibility = "visible"
|
|
toggle_hint = "Switcher %key%"
|
|
toggle_hint_color = "dark gray"
|
|
toggle_hint_modifiers = ""
|
|
include_tty_shell = false
|
|
remember = true
|
|
show_movers = true
|
|
mover_color = "dark gray"
|
|
mover_modifiers = ""
|
|
mover_color_focused = "orange"
|
|
mover_modifiers_focused = "bold"
|
|
left_mover = "<"
|
|
right_mover = ">"
|
|
mover_margin = 1
|
|
show_neighbours = true
|
|
neighbour_color = "dark gray"
|
|
neighbour_modifiers = ""
|
|
neighbour_color_focused = "gray"
|
|
neighbour_modifiers_focused = ""
|
|
neighbour_margin = 1
|
|
selected_color = "gray"
|
|
selected_modifiers = "underlined"
|
|
selected_color_focused = "white"
|
|
selected_modifiers_focused = "bold"
|
|
max_display_length = 8
|
|
no_envs_text = "No environments..."
|
|
no_envs_color = "white"
|
|
no_envs_modifiers = ""
|
|
no_envs_color_focused = "red"
|
|
no_envs_modifiers_focused = ""
|
|
|
|
[username_field]
|
|
remember = true
|
|
|
|
[username_field.style]
|
|
show_title = true
|
|
title = "Login"
|
|
title_color = "white"
|
|
content_color = "white"
|
|
title_color_focused = "orange"
|
|
content_color_focused = "orange"
|
|
show_border = true
|
|
border_color = "white"
|
|
border_color_focused = "orange"
|
|
use_max_width = true
|
|
max_width = 48
|
|
|
|
[password_field]
|
|
content_replacement_character = "*"
|
|
|
|
[password_field.style]
|
|
show_title = true
|
|
title = "Password"
|
|
title_color = "white"
|
|
content_color = "white"
|
|
title_color_focused = "orange"
|
|
content_color_focused = "orange"
|
|
show_border = true
|
|
border_color = "white"
|
|
border_color_focused = "orange"
|
|
use_max_width = true
|
|
max_width = 48
|
|
|
|
[x11]
|
|
x11_display = ":1"
|
|
xserver_timeout_secs = 60
|
|
xserver_log_path = "/var/log/latchd.xorg.log"
|
|
xserver_path = "/usr/bin/X"
|
|
xauth_path = "/usr/bin/xauth"
|
|
scripts_path = "/etc/latchd/wms"
|
|
xsetup_path = "/etc/latchd/xsetup.sh"
|
|
xsessions_path = "/usr/share/xsessions"
|
|
|
|
[wayland]
|
|
scripts_path = "/etc/latchd/wayland"
|
|
wayland_sessions_path = "/usr/share/wayland-sessions"
|
|
`
|