Add explicit pipeline configuration imports
This commit is contained in:
@@ -166,22 +166,92 @@ func buildCompositionNode(node *yaml.Node, source, path string) (*compositionNod
|
||||
// list, or final keyed value may have only one base owner, regardless of
|
||||
// whether duplicate values happen to be equal.
|
||||
func mergeAdditiveComposition(base, incoming *compositionDocument) (*compositionDocument, error) {
|
||||
if err := validateCompositionDocument(base, "base"); err != nil {
|
||||
return mergeAdditiveCompositions(base, incoming)
|
||||
}
|
||||
|
||||
// mergeAdditiveCompositions validates the complete base source set before
|
||||
// merging so a conflict names every source that claims the same final path.
|
||||
func mergeAdditiveCompositions(documents ...*compositionDocument) (*compositionDocument, error) {
|
||||
if len(documents) == 0 {
|
||||
return nil, fmt.Errorf("configuration additive base merge requires at least one document")
|
||||
}
|
||||
for index, document := range documents {
|
||||
if err := validateCompositionDocument(document, fmt.Sprintf("base[%d]", index)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := validateAdditiveClaims(documents); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateCompositionDocument(incoming, "incoming"); err != nil {
|
||||
return nil, err
|
||||
|
||||
result := &compositionDocument{
|
||||
root: cloneCompositionNode(documents[0].root),
|
||||
sources: append([]string(nil), documents[0].sources...),
|
||||
}
|
||||
merged, err := mergeAdditiveNodes(cloneCompositionNode(base.root), incoming.root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, incoming := range documents[1:] {
|
||||
merged, err := mergeAdditiveNodes(result.root, incoming.root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.root = merged
|
||||
result.sources = appendUniqueStrings(result.sources, incoming.sources...)
|
||||
}
|
||||
return &compositionDocument{
|
||||
root: merged,
|
||||
sources: appendUniqueStrings(
|
||||
append([]string(nil), base.sources...), incoming.sources...,
|
||||
),
|
||||
}, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func validateAdditiveClaims(documents []*compositionDocument) error {
|
||||
claims := make(map[string][]*compositionNode)
|
||||
for _, document := range documents {
|
||||
appendCompositionClaims(document.root, claims)
|
||||
}
|
||||
paths := make([]string, 0, len(claims))
|
||||
for path := range claims {
|
||||
paths = append(paths, path)
|
||||
}
|
||||
sort.Slice(paths, func(i, j int) bool {
|
||||
leftDepth := compositionPathDepth(paths[i])
|
||||
rightDepth := compositionPathDepth(paths[j])
|
||||
if leftDepth != rightDepth {
|
||||
return leftDepth < rightDepth
|
||||
}
|
||||
return paths[i] < paths[j]
|
||||
})
|
||||
for _, path := range paths {
|
||||
values := claims[path]
|
||||
if len(values) < 2 {
|
||||
continue
|
||||
}
|
||||
allPopulatedMappings := true
|
||||
for _, value := range values {
|
||||
if value.kind != yaml.MappingNode || len(value.fields) == 0 {
|
||||
allPopulatedMappings = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !allPopulatedMappings {
|
||||
return newCompositionConflict("additive base merge", path, values...)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendCompositionClaims(node *compositionNode, claims map[string][]*compositionNode) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
if node.path != "" {
|
||||
claims[node.path] = append(claims[node.path], node)
|
||||
}
|
||||
for _, field := range node.fields {
|
||||
appendCompositionClaims(field.value, claims)
|
||||
}
|
||||
}
|
||||
|
||||
func compositionPathDepth(path string) int {
|
||||
if path == "" {
|
||||
return 0
|
||||
}
|
||||
return strings.Count(path, ".") + strings.Count(path, "[") + 1
|
||||
}
|
||||
|
||||
func mergeAdditiveNodes(base, incoming *compositionNode) (*compositionNode, error) {
|
||||
|
||||
Reference in New Issue
Block a user