Builds: design 47 G §298, §300, §303, §213; lead answer A-217 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
82 lines
2.5 KiB
Go
82 lines
2.5 KiB
Go
package assigngraph
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"slices"
|
|
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// Reverted says a want of module on node at wantFp is a revert (design 47 G §298, §300, A-217): the module had wantFp in an earlier
|
|
// assignment graph revision than the one it now runs from, by the revisions' own numbers. The revision it runs from is the first kept
|
|
// that lists runFp for the module on the node; a want is a revert when it was listed before that, and never listed since.
|
|
func Reverted(ctx context.Context, o Objects, node, module, runFp, wantFp string) (bool, error) {
|
|
if runFp == "" || wantFp == "" || runFp == wantFp {
|
|
return false, nil
|
|
}
|
|
names, err := o.Names(ctx)
|
|
if err != nil {
|
|
return false, fmt.Errorf("the objects %s: %w", RevisionsObjects, err)
|
|
}
|
|
var numbers []int64
|
|
for _, n := range names {
|
|
if r, ok := trunkOf(n); ok {
|
|
numbers = append(numbers, r)
|
|
}
|
|
}
|
|
slices.Sort(numbers)
|
|
var ranFrom, lastWanted int64
|
|
for _, r := range numbers {
|
|
rev, err := ReadRevision(ctx, o, r)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, ref := range rev.Entries {
|
|
if ref.Node != node || ref.Module != module {
|
|
continue
|
|
}
|
|
e, err := ReadEntry(ctx, o, ref.Digest)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
switch e.Fp {
|
|
case runFp:
|
|
if ranFrom == 0 {
|
|
ranFrom = r
|
|
}
|
|
case wantFp:
|
|
lastWanted = r
|
|
}
|
|
}
|
|
}
|
|
return ranFrom != 0 && lastWanted != 0 && lastWanted < ranFrom, nil
|
|
}
|
|
|
|
// FormChanges are the kept data whose `form` differs between the running entry's manifest and the want's (design 47 G §295 to §298,
|
|
// A-217): the entry's manifest whole is read as a manifest and compared by catalogue.FormChanges, so a kept data's form is read from
|
|
// the entry's kept declarations (catalogue.KeptDeclarations), never from a field of the want.
|
|
func FormChanges(running, applied meshcatalog.CatalogEntry) ([]catalogue.FormChange, error) {
|
|
before, err := manifestOf(running)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("the running manifest of %s: %w", running.Module, err)
|
|
}
|
|
after, err := manifestOf(applied)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("the manifest of %s: %w", applied.Module, err)
|
|
}
|
|
return catalogue.FormChanges(before, after), nil
|
|
}
|
|
|
|
func manifestOf(e meshcatalog.CatalogEntry) (catalogue.Manifest, error) {
|
|
var m catalogue.Manifest
|
|
raw, err := json.Marshal(e.Manifest)
|
|
if err != nil {
|
|
return m, err
|
|
}
|
|
err = json.Unmarshal(raw, &m)
|
|
return m, err
|
|
}
|