Feature 57 (config and provisioning): modules declare config and provisions, their files rendered from templates; synced with main (issues of feature 57, 874)
This commit is contained in:
@@ -18,10 +18,18 @@ type manifest struct {
|
||||
Environment struct {
|
||||
Variables map[string]string `json:"variables"`
|
||||
} `json:"environment"`
|
||||
Items []struct {
|
||||
Collection string `json:"collection"`
|
||||
Attributes map[string]string `json:"attributes"`
|
||||
Template string `json:"template"`
|
||||
} `json:"items"`
|
||||
Shell []struct {
|
||||
For, Slot, Code string
|
||||
} `json:"shell"`
|
||||
Resources []map[string]any `json:"resources"`
|
||||
Build struct {
|
||||
Artifacts []map[string]any `json:"artifacts"`
|
||||
} `json:"build"`
|
||||
}
|
||||
|
||||
func readManifest(t *testing.T) manifest {
|
||||
@@ -33,6 +41,23 @@ func readManifest(t *testing.T) manifest {
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The module's code and variables are the templates of its items (design 57 L3, issues 795 and 807).
|
||||
for _, it := range m.Items {
|
||||
text, err := os.ReadFile(filepath.Join("..", "..", it.Template))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parts := strings.Split(it.Collection, ":")
|
||||
switch {
|
||||
case len(parts) == 3 && parts[0] == "shell":
|
||||
m.Shell = append(m.Shell, struct{ For, Slot, Code string }{parts[1], parts[2], string(text)})
|
||||
case it.Collection == "environment" && it.Attributes["kind"] == "variable":
|
||||
if m.Environment.Variables == nil {
|
||||
m.Environment.Variables = map[string]string{}
|
||||
}
|
||||
m.Environment.Variables[it.Attributes["name"]] = strings.TrimSuffix(string(text), "\n")
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -96,9 +121,10 @@ func TestItOwnsTheFilesItsSourcesHoldAndNoQt5Duplicate(t *testing.T) {
|
||||
pkgs = append(pkgs, r["package"].(string))
|
||||
continue
|
||||
}
|
||||
raw, _ := os.ReadFile(filepath.Join("..", "..", "config", sources[id]))
|
||||
if r["content"] != string(raw) || r["into"] != nil || r["owner"] != "${machine:account}" {
|
||||
t.Errorf("%s is not config/%s, whole and the account's", id, sources[id])
|
||||
_, inline := r["content"]
|
||||
if _, err := os.Stat(filepath.Join("..", "..", "files", sources[id])); err != nil || inline ||
|
||||
r["template"] != "files/"+sources[id] || r["into"] != nil || r["owner"] != "${machine:account}" {
|
||||
t.Errorf("%s is not files/%s, whole, as its template, and the account's", id, sources[id])
|
||||
}
|
||||
if strings.Contains(r["path"].(string), "qt5ct") {
|
||||
t.Error("qt5ct: both workstations run Qt 6 programs through qt6ct; a second tool is a duplicate")
|
||||
@@ -107,7 +133,7 @@ func TestItOwnsTheFilesItsSourcesHoldAndNoQt5Duplicate(t *testing.T) {
|
||||
if strings.Join(pkgs, ",") != "gnome-themes-extra,adwaita-icon-theme,adwaita-cursors,qt6ct,xdg-desktop-portal-gtk" {
|
||||
t.Fatalf("%v", pkgs)
|
||||
}
|
||||
qt := readINI(filepath.Join("..", "..", "config", "qt6ct.conf"))
|
||||
qt := readINI(filepath.Join("..", "..", "files", "qt6ct.conf"))
|
||||
if qt["Appearance"]["style"] != "Fusion" || qt["Appearance"]["custom_palette"] != "true" || !strings.Contains(qt["Fonts"]["general"], "Inter,11") {
|
||||
t.Fatalf("%v", qt)
|
||||
}
|
||||
@@ -116,7 +142,7 @@ func TestItOwnsTheFilesItsSourcesHoldAndNoQt5Duplicate(t *testing.T) {
|
||||
t.Fatalf("qt6ct ships no %s", qt["Appearance"]["color_scheme_path"])
|
||||
}
|
||||
}
|
||||
gtk := readINI(filepath.Join("..", "..", "config", "gtk-settings.ini"))["Settings"]
|
||||
gtk := readINI(filepath.Join("..", "..", "files", "gtk-settings.ini"))["Settings"]
|
||||
if gtk["gtk-theme-name"] != "Adwaita" || gtk["gtk-application-prefer-dark-theme"] != "1" || gtk["gtk-font-name"] != "Inter 11" {
|
||||
t.Fatalf("%v", gtk)
|
||||
}
|
||||
@@ -244,3 +270,31 @@ func asJSON(v any) string {
|
||||
b, _ := json.Marshal(v)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// No file resource carries its text inline: each names its template in files/, and the build packs files/
|
||||
// into the one archive the controller reads the templates back from (novox/hq ADR 0349 §2).
|
||||
func TestEveryFileTakesItsTextFromATemplate(t *testing.T) {
|
||||
m := readManifest(t)
|
||||
for _, r := range m.Resources {
|
||||
if _, inline := r["content"]; inline {
|
||||
t.Errorf("resource %v keeps its text inline: keep it in files/ and name it as the template", r["id"])
|
||||
}
|
||||
if name, ok := r["template"].(string); ok {
|
||||
if _, err := os.Stat(filepath.Join("..", "..", name)); err != nil {
|
||||
t.Errorf("resource %v names %s: %v", r["id"], name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
packs := 0
|
||||
for _, a := range m.Build.Artifacts {
|
||||
if a["kind"] == "archive" && a["from"] == "files" {
|
||||
packs++
|
||||
if a["name"] != "files" {
|
||||
t.Errorf("the templates archive is named %v, not files", a["name"])
|
||||
}
|
||||
}
|
||||
}
|
||||
if packs != 1 {
|
||||
t.Errorf("the build packs files/ into %d archives, not one", packs)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user