Read a manifest's fallback to a predefined key in the composer as the indexer reads it, or against the list a request or -catalogue gives: a run never holds the catalogue's predefined.json, and the composition refused pacman and xterm for it (ADR 0348 §7)
This commit is contained in:
@@ -28,6 +28,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/composer"
|
||||
)
|
||||
|
||||
@@ -96,6 +97,15 @@ func run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
|
||||
req.Cases[0].Manifests[name] = m
|
||||
}
|
||||
}
|
||||
// The catalogue's list of predefined keys is the one its manifests' fallbacks are judged against (ADR 0348 §7).
|
||||
if req.Predefined == nil {
|
||||
list, err := catalogue.ReadPredefined(*catalogueDir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(stderr, "mesh-compose:", err)
|
||||
return 1
|
||||
}
|
||||
req.Predefined = list
|
||||
}
|
||||
}
|
||||
req.Machines = append(req.Machines, machines...)
|
||||
if *depth != "" {
|
||||
|
||||
@@ -114,7 +114,8 @@ func TestTheCommandAnswersWhatTheLinkedCompositionAnswers(t *testing.T) {
|
||||
in := meshOf()
|
||||
in.Catalogue = map[string]catalogue.Manifest{}
|
||||
for name, m := range r.Cases[0].Manifests {
|
||||
parsed, err := catalogue.ParseManifest(m.Raw)
|
||||
// A request without a list of predefined keys reads a fallback as the indexer does (Request.Predefined).
|
||||
parsed, err := catalogue.ParseManifestForInputs(m.Raw)
|
||||
got := v.Cases[0].Manifests[name]
|
||||
if (err == nil) != got.Accepted || (err != nil && err.Error() != got.Refused) {
|
||||
t.Errorf("%s: the manifest of %s: linked %v, command %+v", depth, name, err, got)
|
||||
@@ -309,3 +310,38 @@ func TestTheCommandRunsWithNoNetwork(t *testing.T) {
|
||||
sort.Strings(names)
|
||||
t.Logf("composed with no network: %v", names)
|
||||
}
|
||||
|
||||
// -catalogue judges a fallback to a predefined key against the predefined.json at the checkout's root (ADR 0348 §7):
|
||||
// xterm (mesh-catalog at 835bf22b) falls back to "font-size", accepted where the root lists it and refused where the
|
||||
// root's list does not.
|
||||
func TestACatalogueCheckoutJudgesFallbacksAgainstItsPredefinedKeys(t *testing.T) {
|
||||
raw, err := os.ReadFile("../../catalogue/testdata/catalogue-835bf22b-xterm.module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, c := range []struct {
|
||||
list string
|
||||
want bool
|
||||
}{
|
||||
{`{"font-size": {"type": "number", "description": "the desktop's font size"}}`, true},
|
||||
{`{"font-family": {"type": "string", "description": "the desktop's font"}}`, false},
|
||||
} {
|
||||
dir := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(dir, "modules", "xterm"), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "modules", "xterm", "module.json"), raw, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, catalogue.PredefinedFile), []byte(c.list), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
code, v, stderr := runJSON(t, []string{"-catalogue", dir}, nil)
|
||||
if code != 0 {
|
||||
t.Fatalf("exit %d: %s", code, stderr)
|
||||
}
|
||||
if got := v.Cases[0].Manifests["xterm"]; got.Accepted != c.want {
|
||||
t.Errorf("predefined.json %s: xterm %+v, want accepted %v", c.list, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-4
@@ -55,6 +55,12 @@ type Request struct {
|
||||
HoldingsFromClaims bool `json:"holdings_from_claims,omitempty"`
|
||||
// Declarations asks each composed machine's declared paths (DepthCompose only).
|
||||
Declarations bool `json:"declarations,omitempty"`
|
||||
// Predefined is the list of predefined keys at the catalogue's root (predefined.json, novox/hq ADR 0348 §7) that
|
||||
// every config value falling back to a key is judged against, when the asker has it (mesh-compose -catalogue
|
||||
// reads it). Without it a fallback is read as catalogue.ParseManifestForInputs reads it: against the list the mesh
|
||||
// published when this process holds one, else each key as its value declares it, for the merge gate judges the
|
||||
// fallback in the catalogue and a manifest that only carries one is not refused here.
|
||||
Predefined catalogue.PredefinedList `json:"predefined,omitempty"`
|
||||
}
|
||||
|
||||
// Case is one catalogue composed: every module's manifest by name, and per node the manifests kept at the build it runs.
|
||||
@@ -209,13 +215,22 @@ func Run(r Request) (Verdict, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func parse(m map[string]Manifest, reads map[string]ManifestRead) (map[string]catalogue.Manifest, error) {
|
||||
// readManifest reads one manifest as this run reads every one: against the request's list of predefined keys when it
|
||||
// has one, else as the indexer and the builder read it (Request.Predefined).
|
||||
func readManifest(raw []byte, predefined catalogue.PredefinedList) (catalogue.Manifest, error) {
|
||||
if predefined != nil {
|
||||
return catalogue.ParseManifestWith(raw, predefined)
|
||||
}
|
||||
return catalogue.ParseManifestForInputs(raw)
|
||||
}
|
||||
|
||||
func parse(m map[string]Manifest, reads map[string]ManifestRead, predefined catalogue.PredefinedList) (map[string]catalogue.Manifest, error) {
|
||||
out := map[string]catalogue.Manifest{}
|
||||
for name, man := range m {
|
||||
if len(man.Raw) == 0 {
|
||||
return nil, fmt.Errorf("%w: %s (digest %s)", ErrUnfilled, name, man.Digest)
|
||||
}
|
||||
parsed, err := catalogue.ParseManifest(man.Raw)
|
||||
parsed, err := readManifest(man.Raw, predefined)
|
||||
if reads != nil {
|
||||
if err != nil {
|
||||
reads[name] = ManifestRead{Refused: err.Error()}
|
||||
@@ -232,7 +247,7 @@ func parse(m map[string]Manifest, reads map[string]ManifestRead) (map[string]cat
|
||||
|
||||
func runCase(r Request, c Case, depth string) (CaseVerdict, error) {
|
||||
cv := CaseVerdict{Name: c.Name, Manifests: map[string]ManifestRead{}}
|
||||
shelf, err := parse(c.Manifests, cv.Manifests)
|
||||
shelf, err := parse(c.Manifests, cv.Manifests, r.Predefined)
|
||||
if err != nil {
|
||||
return CaseVerdict{}, err
|
||||
}
|
||||
@@ -243,7 +258,7 @@ func runCase(r Request, c Case, depth string) (CaseVerdict, error) {
|
||||
for i := range in.Nodes {
|
||||
in.Nodes[i].Kept = nil
|
||||
if kept := c.Kept[in.Nodes[i].Name]; len(kept) > 0 {
|
||||
k, err := parse(kept, nil)
|
||||
k, err := parse(kept, nil, r.Predefined)
|
||||
if err != nil {
|
||||
return CaseVerdict{}, err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package composer
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -104,3 +105,33 @@ func TestARequestItCannotRunIsRefused(t *testing.T) {
|
||||
t.Fatalf("a request with no machines: %+v, %v", v, err)
|
||||
}
|
||||
}
|
||||
|
||||
// A manifest whose config value falls back to a predefined key (novox/hq ADR 0348 §7) is read, not refused for the
|
||||
// list of predefined keys at the catalogue's root that a run is never handed with its manifests: the merge gate judges
|
||||
// the fallback in the catalogue. xterm's module.json from mesh-catalog at 835bf22b falls back to "font-size"; a group
|
||||
// touching xterm or pacman failed its composition on this (group check 18df81380db3). A list in the request is the one
|
||||
// judged against, so a fallback it does not name is still refused.
|
||||
func TestAManifestFallingBackToAPredefinedKeyIsRead(t *testing.T) {
|
||||
raw, err := os.ReadFile("../catalogue/testdata/catalogue-835bf22b-xterm.module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(raw), `"predefined"`) {
|
||||
t.Fatal("the fixture names no predefined key")
|
||||
}
|
||||
r := Request{V: Version, Cases: []Case{{Name: "change", Manifests: map[string]Manifest{"xterm": {Raw: raw}}}}}
|
||||
v, err := Run(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := v.Cases[0].Manifests["xterm"]; !got.Accepted {
|
||||
t.Fatalf("xterm: %+v, want accepted", got)
|
||||
}
|
||||
r.Predefined = catalogue.PredefinedList{"something-else": {Type: "string", Description: "x"}}
|
||||
if v, err = Run(r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := v.Cases[0].Manifests["xterm"]; got.Accepted || !strings.Contains(got.Refused, "not on the list of predefined keys") {
|
||||
t.Fatalf("xterm judged against a list without its key: %+v, want refused naming the list", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user