120 lines
4.3 KiB
Go
120 lines
4.3 KiB
Go
package engine
|
|
|
|
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
|
|
|
// Retain source history at original paths. Structural operations are held once
|
|
// per relationship and projected onto a requested destination path only when
|
|
// History or Explain is queried.
|
|
func applyInheritanceMetadata(metadata *Metadata, raw *document.Node, rawOrigins map[string]Origin, overlays []overlayRecord, expansion *inheritanceScope) {
|
|
if metadata == nil || expansion == nil {
|
|
return
|
|
}
|
|
sourceView := Metadata{
|
|
fields: make(map[string]FieldInfo),
|
|
history: metadata.history,
|
|
}
|
|
walkDocument(raw, Path{}, func(path Path, node *document.Node) {
|
|
origin, found := rawOrigins[path.String()]
|
|
if !found {
|
|
origin = Origin{Layer: LayerBase, Locations: []Location{publicLocation(node.Location)}}
|
|
}
|
|
sourceView.fields[path.String()] = FieldInfo{Explicit: true, Null: node.Kind == document.Null, Origin: cloneOrigin(origin)}
|
|
})
|
|
applyOverlayMetadata(&sourceView, overlays)
|
|
metadata.history = sourceView.history
|
|
metadata.inheritance = append([]inheritanceOperation(nil), expansion.operations...)
|
|
}
|
|
|
|
func historyWithInheritance(path Path, stored []Change, operations []inheritanceOperation) []Change {
|
|
split := len(stored)
|
|
for index, change := range stored {
|
|
if change.Origin.Layer == LayerResolution {
|
|
split = index
|
|
break
|
|
}
|
|
}
|
|
history := cloneChanges(stored[:split])
|
|
for _, operation := range operations {
|
|
for _, change := range projectedInheritanceChanges(path, operation) {
|
|
if len(history) != 0 {
|
|
change.Previous = []Origin{cloneOrigin(history[len(history)-1].Origin)}
|
|
}
|
|
history = append(history, change)
|
|
}
|
|
}
|
|
for _, change := range stored[split:] {
|
|
cloned := cloneChange(change)
|
|
if len(history) != 0 {
|
|
cloned.Previous = []Origin{cloneOrigin(history[len(history)-1].Origin)}
|
|
}
|
|
history = append(history, cloned)
|
|
}
|
|
return history
|
|
}
|
|
|
|
func projectedInheritanceChanges(query Path, operation inheritanceOperation) []Change {
|
|
if operation.control != nil {
|
|
if !pathsIntersect(operation.control.path, query) {
|
|
return nil
|
|
}
|
|
origin := cloneOrigin(operation.controlOrigin)
|
|
origin.Operation = ChangeInheritance
|
|
origin.Inheritance = projectInheritanceSteps(origin)
|
|
return []Change{{Path: operation.control.path.clone(), Origin: origin,
|
|
Dependencies: []Path{operation.control.path.clone()}}}
|
|
}
|
|
if operation.transfer == nil || !pathsIntersect(operation.transfer.to, query) {
|
|
return nil
|
|
}
|
|
path := query
|
|
if pathContains(query, operation.transfer.to) {
|
|
path = operation.transfer.to
|
|
}
|
|
var changes []Change
|
|
parent, parentFound := transferredOperationOrigin(operation, path)
|
|
if parentFound {
|
|
parent.Operation = ChangeInheritance
|
|
parent.Inheritance = projectInheritanceSteps(parent)
|
|
changes = append(changes, Change{
|
|
Path: path.clone(), Origin: parent,
|
|
Dependencies: []Path{operation.transfer.from.clone(), operation.transfer.reference.clone()},
|
|
})
|
|
}
|
|
effective, effectiveFound := operation.effectiveOrigins[path.String()]
|
|
if effectiveFound {
|
|
effective = cloneOrigin(effective)
|
|
effective.Operation = ChangeInheritance
|
|
}
|
|
if effectiveFound && (!parentFound || !originContainedBy(effective, parent)) {
|
|
effective.Inheritance = projectInheritanceSteps(effective)
|
|
changes = append(changes, Change{
|
|
Path: path.clone(), Origin: effective,
|
|
Dependencies: []Path{operation.transfer.reference.clone()},
|
|
})
|
|
} else if parentFound && !effectiveFound {
|
|
removed := cloneOrigin(operation.effectiveOrigins[operation.transfer.to.String()])
|
|
removed.Operation = ChangeInheritance
|
|
removed.Inheritance = projectInheritanceSteps(removed)
|
|
changes = append(changes, Change{
|
|
Path: operation.transfer.to.clone(), Origin: removed,
|
|
Dependencies: []Path{operation.transfer.reference.clone()},
|
|
})
|
|
}
|
|
return changes
|
|
}
|
|
|
|
func transferredOperationOrigin(operation inheritanceOperation, destination Path) (Origin, bool) {
|
|
relative, ok := relativeHistoryPath(operation.transfer.to, destination)
|
|
if !ok {
|
|
return Origin{}, false
|
|
}
|
|
source := appendInheritancePath(operation.transfer.from, relative)
|
|
origin, found := operation.parentOrigins[source.String()]
|
|
if !found {
|
|
return Origin{}, false
|
|
}
|
|
transferred := transferredInheritanceOrigins(map[string]Origin{source.String(): origin},
|
|
operation.transfer.from, operation.transfer.to, *operation.transfer)
|
|
return transferred[destination.String()], true
|
|
}
|