Pass effective destinations through import traversal

This commit is contained in:
2026-10-14 17:21:07 +00:00
parent a8beb3e620
commit 49c0c6d908
7 changed files with 189 additions and 35 deletions

View File

@@ -45,11 +45,10 @@ type importAccounting struct {
}
type importTraversal struct {
access *filesystemAccess
accounting *importAccounting
limits importLimits
rule *VersionRule
destination Path
access *filesystemAccess
accounting *importAccounting
limits importLimits
rule *VersionRule
documents []*document.Node
sources []SourceInfo
@@ -120,10 +119,9 @@ func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath
accounting.nodes += countInputNodes(main.document)
state := importTraversal{
access: access, accounting: accounting, limits: limits, rule: rule,
destination: destination.clone(),
documents: make([]*document.Node, 0, 1),
sources: []SourceInfo{mainInfo},
active: make(map[resourceIdentity]int), visited: visited,
documents: make([]*document.Node, 0, 1),
sources: []SourceInfo{mainInfo},
active: make(map[resourceIdentity]int), visited: visited,
}
if state.visited == nil {
state.visited = make(map[resourceIdentity]importRoute)
@@ -143,8 +141,8 @@ func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath
state.stack = append(state.stack, mainRoute)
body, declarations, diagnostics := splitImportDirectives(main.document)
if len(diagnostics) == 0 {
_, placed, err := placeDocument(body, state.destination, body.Location, maxDocumentDepth, maxDocumentNodes)
placementNodes := destinationWrapperNodeCount(state.destination)
_, placed, err := placeDocument(body, destination, body.Location, maxDocumentDepth, maxDocumentNodes)
placementNodes := destinationWrapperNodeCount(destination)
if err != nil {
diagnostics = []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, main.source.ID, "configuration exceeds the source depth or node limit after destination placement")}
} else if accounting.nodes+placementNodes > limits.nodes {
@@ -152,7 +150,7 @@ func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath
} else {
accounting.nodes += placementNodes
state.documents = append(state.documents, placed)
diagnostics = state.walkDeclarations(basePath, declarations, 0)
diagnostics = state.walkDeclarations(basePath, declarations, 0, destination)
}
}
@@ -187,8 +185,9 @@ func (s *importTraversal) checkInitialLimits() *Diagnostic {
return nil
}
func (s *importTraversal) walkDeclarations(basePath string, declarations []importDeclaration, depth int) []Diagnostic {
func (s *importTraversal) walkDeclarations(basePath string, declarations []importDeclaration, depth int, parentDestination Path) []Diagnostic {
for _, declaration := range declarations {
childDestination := appendDestination(parentDestination, declaration.destination)
if declaration.glob != "" {
matches, diagnostics := s.expandImportGlob(basePath, declaration)
if len(diagnostics) != 0 {
@@ -205,20 +204,20 @@ func (s *importTraversal) walkDeclarations(basePath string, declarations []impor
matched := declaration
matched.path = match
matched.glob = ""
if diagnostics := s.visitPath(basePath, matched, depth+1); len(diagnostics) != 0 {
if diagnostics := s.visitPath(basePath, matched, childDestination, depth+1); len(diagnostics) != 0 {
return diagnostics
}
}
continue
}
if diagnostics := s.visitPath(basePath, declaration, depth+1); len(diagnostics) != 0 {
if diagnostics := s.visitPath(basePath, declaration, childDestination, depth+1); len(diagnostics) != 0 {
return diagnostics
}
}
return nil
}
func (s *importTraversal) visitPath(basePath string, declaration importDeclaration, depth int) []Diagnostic {
func (s *importTraversal) visitPath(basePath string, declaration importDeclaration, destination Path, depth int) []Diagnostic {
location := declaration.location
if depth > s.limits.depth {
return []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the active import-depth limit", &location)}
@@ -272,7 +271,7 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati
kind = SourceKindFilesystem
label = s.access.label + "/" + canonical
}
info := SourceInfo{ID: sourceID, Label: label, Path: canonical, Destination: s.destination.clone(), Layer: LayerBase, Kind: kind, ImportedFrom: &location}
info := SourceInfo{ID: sourceID, Label: label, Path: canonical, Destination: destination.clone(), Layer: LayerBase, Kind: kind, ImportedFrom: &location}
if kind == SourceKindFilesystem {
info.namespace = s.access.token
}
@@ -303,11 +302,11 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati
if len(diagnostics) != 0 {
return diagnostics
}
_, placed, err := placeDocument(body, s.destination, body.Location, maxDocumentDepth, maxDocumentNodes)
_, placed, err := placeDocument(body, destination, body.Location, maxDocumentDepth, maxDocumentNodes)
if err != nil {
return []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the source depth or node limit after destination placement", &location)}
}
placementNodes := destinationWrapperNodeCount(s.destination)
placementNodes := destinationWrapperNodeCount(destination)
if s.accounting.nodes+placementNodes > s.limits.nodes {
return []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", &location)}
}
@@ -325,7 +324,7 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati
s.active[identity] = len(s.stack)
s.visited[identity] = route
s.stack = append(s.stack, route)
diagnostics = s.walkDeclarations(s.access.dir(canonical), declarations, depth)
diagnostics = s.walkDeclarations(s.access.dir(canonical), declarations, depth, destination)
delete(s.active, identity)
s.stack = s.stack[:len(s.stack)-1]
return diagnostics