feat: drop-in support for custom templates
User templates can now be added without rebuilding: drop a script into ~/.config/motd-assist/templates/ and reference it from a preset via "install": "<filename>". Same-name files override built-ins; new files are picked up by the running TUI via 'r'. `motd-assist templates` lists known templates and creates the drop-in directory. Apply plans now embed the resolved template content (Plan.ResolveContents) so the sudo/root process never needs to read user config; snapshots store installed script content so restore works under sudo as well. Validation rejects plans with unresolved content.
This commit is contained in:
parent
d56659e21a
commit
303c49b484
10 changed files with 375 additions and 48 deletions
77
internal/assets/assets_test.go
Normal file
77
internal/assets/assets_test.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package assets
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDropInAndOverride(t *testing.T) {
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
dir, err := EnsureTemplatesDir()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "mein-header"),
|
||||
[]byte("#!/bin/sh\necho custom\n"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "footer"),
|
||||
[]byte("#!/bin/sh\necho myfooter\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Drop-in wird gefunden.
|
||||
c, ok := ScriptContent("mein-header")
|
||||
if !ok || !strings.Contains(c, "custom") {
|
||||
t.Errorf("ScriptContent(mein-header) = %q, %v", c, ok)
|
||||
}
|
||||
|
||||
// Gleichnamige User-Vorlage überdeckt das Built-in.
|
||||
c, ok = ScriptContent("footer")
|
||||
if !ok || !strings.Contains(c, "myfooter") {
|
||||
t.Errorf("Override greift nicht: %q, %v", c, ok)
|
||||
}
|
||||
|
||||
// Übrige Built-ins bleiben erreichbar.
|
||||
if c, ok = ScriptContent("brand-header"); !ok || !strings.Contains(c, "brand-header") {
|
||||
t.Errorf("Built-in fehlt: %q, %v", c, ok)
|
||||
}
|
||||
|
||||
// Namensliste enthält die Drop-in-Vorlage.
|
||||
var found bool
|
||||
for _, n := range ScriptNames() {
|
||||
if n == "mein-header" {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Error("mein-header fehlt in ScriptNames()")
|
||||
}
|
||||
|
||||
// MatchScript erkennt Drop-in-Inhalt.
|
||||
name, ok := MatchScript("#!/bin/sh\necho custom\n")
|
||||
if !ok || name != "mein-header" {
|
||||
t.Errorf("MatchScript = %q, %v", name, ok)
|
||||
}
|
||||
|
||||
// Templates() markiert die Quellen richtig.
|
||||
sources := map[string]string{}
|
||||
for _, tpl := range Templates() {
|
||||
sources[tpl.Name] = tpl.Source
|
||||
}
|
||||
if sources["mein-header"] != "user" || sources["footer"] != "user" || sources["brand-header"] != "builtin" {
|
||||
t.Errorf("Quellen falsch: %+v", sources)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropInDirMissingIsNoError(t *testing.T) {
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(t.TempDir(), "leer"))
|
||||
if _, ok := ScriptContent("gibt-es-nicht"); ok {
|
||||
t.Error("unbekannte Vorlage darf nicht gefunden werden")
|
||||
}
|
||||
if len(Templates()) == 0 {
|
||||
t.Error("Built-ins sollten ohne Drop-in-Ordner weiter existieren")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue