An assignment places a module's directories and its accesses (hq 153) #176

Merged
mesh-admin merged 3 commits from feat/153-an-assignment-places-directories-and-accesses into main 2026-09-30 22:03:33 +00:00
Showing only changes of commit 52c18f7a45 - Show all commits
+50
View File
@@ -60,6 +60,11 @@ func TestPlacedDirectoriesKeepTheirPaths(t *testing.T) {
// (issue 119's conversion), and what must not move is the path a machine sees. // (issue 119's conversion), and what must not move is the path a machine sees.
was = resolvedTree(was, dirsFor(earlier, Rendering{}), module, t) was = resolvedTree(was, dirsFor(earlier, Rendering{}), module, t)
resolved := resolvedTree(is, dirsFor(m, Rendering{}), module, t) resolved := resolvedTree(is, dirsFor(m, Rendering{}), module, t)
// An access named by id resolves to the path the definition still carries as its default
// (issue 153) — the same rule as a placed directory: an assignment that says nothing moves
// nothing.
was = accessesResolved(was, earlier)
resolved = accessesResolved(resolved, m)
if !reflect.DeepEqual(was, resolved) { if !reflect.DeepEqual(was, resolved) {
wasJSON, _ := json.MarshalIndent(was, "", " ") wasJSON, _ := json.MarshalIndent(was, "", " ")
isJSON, _ := json.MarshalIndent(resolved, "", " ") isJSON, _ := json.MarshalIndent(resolved, "", " ")
@@ -128,3 +133,48 @@ func firstDifference(a, b string) string {
} }
return "(the difference is beyond the shorter document)" return "(the difference is beyond the shorter document)"
} }
// accessesResolved fills every ${access:<id>} with the default path the definition carries for that
// access, and drops the id, so a manifest that names its accesses is compared by the paths a machine
// with no placement receives.
func accessesResolved(node any, m Manifest) any {
defaults := map[string]string{}
for _, a := range m.Accesses {
if a.ID != "" && a.Path != "" {
defaults[a.ID] = a.Path
}
}
var walk func(any) any
walk = func(n any) any {
switch v := n.(type) {
case map[string]any:
out := map[string]any{}
for k, child := range v {
if k == "id" {
if _, isAccess := v["mode"]; isAccess && v["type"] == nil {
if _, hasPath := v["path"]; hasPath {
continue
}
}
}
out[k] = walk(child)
}
return out
case []any:
out := make([]any, len(v))
for i, child := range v {
out[i] = walk(child)
}
return out
case string:
return accessRef.ReplaceAllStringFunc(v, func(ref string) string {
if p, ok := defaults[accessRef.FindStringSubmatch(ref)[1]]; ok {
return p
}
return ref
})
}
return n
}
return walk(node)
}