89 lines
3.6 KiB
Go
89 lines
3.6 KiB
Go
package locationregistry
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/semanticreconcile"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/locations/identity"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
|
|
)
|
|
|
|
func reconciliationInputs(records []normalizedRecord) ([]semanticreconcile.Candidate, []semanticreconcile.Record[dnd.Location], error) {
|
|
candidates := make([]semanticreconcile.Candidate, len(records))
|
|
envelopes := make([]semanticreconcile.Record[dnd.Location], len(records))
|
|
for index, record := range records {
|
|
candidates[index] = semanticreconcile.Candidate{
|
|
Label: record.location.Name,
|
|
SourceRefs: cloneSourceRefs(record.location.SourceRefs),
|
|
}
|
|
envelope, err := semanticreconcile.NewRecord(record.location, record.inputIndexes, record.earliest, cloneLocation)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("record %d: %w", index, err)
|
|
}
|
|
envelopes[index] = envelope
|
|
}
|
|
return candidates, envelopes, nil
|
|
}
|
|
|
|
func applyReconciliationPlan(plan semanticreconcile.Plan, records []normalizedRecord, envelopes []semanticreconcile.Record[dnd.Location], order shared.SourceRefOrder) ([]normalizedRecord, []contracts.Warning, error) {
|
|
application, err := semanticreconcile.ApplyPlan(plan, envelopes, semanticreconcile.ApplicationPolicy[dnd.Location]{
|
|
CloneValue: cloneLocation,
|
|
ConsolidateGroup: func(members []dnd.Location, canonical dnd.Location) (dnd.Location, error) {
|
|
output := cloneLocation(canonical)
|
|
output.SourceRefs = nil
|
|
for _, member := range members {
|
|
output.SourceRefs = append(output.SourceRefs, member.SourceRefs...)
|
|
}
|
|
output.SourceRefs = order.Canonicalize(output.SourceRefs)
|
|
output.ID = identity.DeriveID(output.Name, output.SourceRefs)
|
|
return output, nil
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
applied := application.Records()
|
|
output := make([]normalizedRecord, len(applied))
|
|
for index, record := range applied {
|
|
output[index] = normalizedRecord{
|
|
location: record.Value(),
|
|
inputIndexes: record.OriginalInputIndexes(),
|
|
earliest: record.EarliestInputPosition(),
|
|
}
|
|
}
|
|
warnings := make([]contracts.Warning, 0, len(application.AppliedGroups()))
|
|
for _, event := range application.AppliedGroups() {
|
|
provenance := event.Provenance()
|
|
warnings = append(warnings, semanticDuplicateWarning(provenance, records[provenance.CanonicalPosition()]))
|
|
}
|
|
return output, warnings, nil
|
|
}
|
|
|
|
func reconciliationIssues(issues []semanticreconcile.Issue) []string {
|
|
details := make([]string, len(issues))
|
|
for index, issue := range issues {
|
|
details[index] = fmt.Sprintf("group %d: %s", issue.GroupIndex, issue.Category)
|
|
}
|
|
return details
|
|
}
|
|
|
|
func semanticDuplicateWarning(provenance semanticreconcile.GroupProvenance, canonical normalizedRecord) contracts.Warning {
|
|
inputIndexes := provenance.OriginalInputIndexes()
|
|
details := make([]string, 0, len(inputIndexes)+1)
|
|
for _, inputIndex := range inputIndexes {
|
|
details = append(details, fmt.Sprintf("input index %d", inputIndex))
|
|
}
|
|
if canonical.earliest != provenance.EarliestInputPosition() {
|
|
details = append(details, fmt.Sprintf("canonical display name from input index %d", canonical.earliest))
|
|
}
|
|
return contracts.Warning{
|
|
Scope: locationScope(provenance.EarliestInputPosition()),
|
|
ReasonCode: ReasonCodeDuplicateLocationCollapsed,
|
|
Message: diagnostics.Aggregate("semantic duplicate consolidation", details),
|
|
}
|
|
}
|