Registry milestone: mesh-sdk (issue 1966) #167
@@ -163,12 +163,8 @@ func ManifestNeeds(raw []byte) ([]string, error) {
|
||||
return nil, err
|
||||
}
|
||||
used := map[string]bool{}
|
||||
for _, f := range referenceForms {
|
||||
if bytes.Contains(raw, []byte("${"+f+":")) {
|
||||
used[ReadForm+f] = true
|
||||
}
|
||||
}
|
||||
if ofSeatReach.Match(raw) || claimsAtMesh(top, ContainerImageRegistrySeat) {
|
||||
textNeeds(raw, used)
|
||||
if claimsAtMesh(top, ContainerImageRegistrySeat) {
|
||||
used[ReadForm+ReferenceFormSeatReach] = true
|
||||
}
|
||||
if _, has := top[ConfigField]; has || takesConfigKey.Match(raw) {
|
||||
@@ -429,6 +425,39 @@ func asList(v any) []any {
|
||||
return list
|
||||
}
|
||||
|
||||
// textNeeds adds the reference forms a manifest's or a template's text writes to used: a form the engine fills in a
|
||||
// file's text is read there whether the text is inline or in a template file.
|
||||
func textNeeds(text []byte, used map[string]bool) {
|
||||
for _, f := range referenceForms {
|
||||
if bytes.Contains(text, []byte("${"+f+":")) {
|
||||
used[ReadForm+f] = true
|
||||
}
|
||||
}
|
||||
if ofSeatReach.Match(text) {
|
||||
used[ReadForm+ReferenceFormSeatReach] = true
|
||||
}
|
||||
}
|
||||
|
||||
// ModuleNeeds is ManifestNeeds of a module whose files take their text from templates (template.go): what the manifest
|
||||
// needs and what each template's text writes, by template path (TemplatePaths), sorted. A module's needs are both: an
|
||||
// engine renders the template's text as it renders inline content, so a template naming ${seat:x:reach} needs the
|
||||
// reading as the same content inline does, though the manifest itself is unchanged (novox/hq ADR 0632 §2). A template
|
||||
// named and not given is no need; the reader of the files says it could not read one.
|
||||
func ModuleNeeds(raw []byte, templates map[string]string) ([]string, error) {
|
||||
needs, err := ManifestNeeds(raw)
|
||||
if err != nil || len(templates) == 0 {
|
||||
return needs, err
|
||||
}
|
||||
used := map[string]bool{}
|
||||
for _, n := range needs {
|
||||
used[n] = true
|
||||
}
|
||||
for _, text := range templates {
|
||||
textNeeds([]byte(text), used)
|
||||
}
|
||||
return sortedSet(used), nil
|
||||
}
|
||||
|
||||
func sortedSet(set map[string]bool) []string {
|
||||
out := make([]string, 0, len(set))
|
||||
for k := range set {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package catalogue
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
@@ -87,12 +88,26 @@ func TestOwnManifestUsesNoWordTheRunningControllerRefuses(t *testing.T) {
|
||||
{"the store's holder", `{"module":"distribution","version":"1","claims":[{"name":"container-image-registry",` +
|
||||
`"scope":"mesh","serves":["list"]}],"listens":[{"name":"registry","port":5000,"from":"mesh"}]}`,
|
||||
[]string{"form:seat-reach", "seat:container-image-registry"}, []string{"form:seat-reach", "seat:container-image-registry"}},
|
||||
// docker's daemon file as ADR 0632 leaves it: the manifest unchanged, its template naming the image seat's reach;
|
||||
// TemplatePaths names the template a reader of the files reads.
|
||||
{"a template naming a seat's reach", `{"module":"d","version":"1","resources":[{"id":"daemon","type":"file",` +
|
||||
`"path":"/etc/d.json","template":"files/daemon.json"}]}`, []string{"form:seat", "form:seat-reach"},
|
||||
[]string{"form:seat-reach"}},
|
||||
{"a word this contract does not know", `{"module":"u","version":"1","newer-word":{"inside":1}}`, []string{"word:module"}, nil},
|
||||
} {
|
||||
needs, err := ManifestNeeds([]byte(row.raw))
|
||||
templates := map[string]map[string]string{ // the templates' text a row's module names
|
||||
"a template naming a seat's reach": {"files/daemon.json": `{"x":"${seat:container-image-registry:reach}"}`},
|
||||
}[row.why]
|
||||
needs, err := ModuleNeeds([]byte(row.raw), templates)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", row.why, err)
|
||||
}
|
||||
if templates != nil {
|
||||
m, err := Decode([]byte(row.raw))
|
||||
if paths := TemplatePaths(m); err != nil || !slices.Equal(paths, slices.Sorted(maps.Keys(templates))) {
|
||||
t.Errorf("%s: TemplatePaths = %v (%v), want %v", row.why, paths, err, slices.Sorted(maps.Keys(templates)))
|
||||
}
|
||||
}
|
||||
for _, n := range row.needs {
|
||||
if !slices.Contains(needs, n) {
|
||||
t.Errorf("%s: needs %v, not %s", row.why, needs, n)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -184,6 +185,25 @@ func fillItemTemplates(m Manifest, items []Item, text func(string) (string, bool
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// TemplatePaths is every template the manifest's files and items name, by its path in the module's directory, sorted
|
||||
// and once each: what a reader of the module's files reads for ModuleNeeds. A template whose name is wrong is left out;
|
||||
// the judge refuses it by name.
|
||||
func TemplatePaths(m Manifest) []string {
|
||||
var out []string
|
||||
for _, r := range m.Resources {
|
||||
if name, has, wrong := templateOf(m.Module, m.TemplatesDir(), r); has && wrong == "" {
|
||||
out = append(out, name)
|
||||
}
|
||||
}
|
||||
for _, it := range m.Items {
|
||||
if it.Template != "" && itemTemplateProblem(m, it.Template) == "" {
|
||||
out = append(out, it.Template)
|
||||
}
|
||||
}
|
||||
slices.Sort(out)
|
||||
return slices.Compact(out)
|
||||
}
|
||||
|
||||
// ReadTemplates is the text of each template the manifest names, read from the module's directory in a repository tree,
|
||||
// by template path. Refused by name: a template the directory lacks, and anything under its templates directory
|
||||
// (TemplatesDir) the build's packing refuses — that directory itself, or any directory or file under it, that is a
|
||||
|
||||
@@ -594,6 +594,10 @@ type Forge struct {
|
||||
// relative to it (novox/hq ADR 0465 clause 1). Older writers send neither.
|
||||
Manifests map[string]string `json:"manifests,omitempty"`
|
||||
Locks map[string]map[string]string `json:"locks,omitempty"`
|
||||
// Needs are, of each such directory whose manifest names templates, the reader capabilities of the module whole:
|
||||
// its manifest's and its templates' text's at the same commit (catalogue.ModuleNeeds; novox/hq ADR 0632 §2). The
|
||||
// indexer takes them over the manifest's own; a directory absent, or an older writer, has the manifest's alone.
|
||||
Needs map[string][]string `json:"needs,omitempty"`
|
||||
// Paths are, of each module directory whose manifest names paths on every artifact, each named path's git object
|
||||
// id at the same commit as its manifest, by path relative to the directory (novox/hq ADR 0499 clause 3). The
|
||||
// indexer names the paths; a message without them gives such a module none. Older writers send none.
|
||||
|
||||
Reference in New Issue
Block a user