Carry destinations through imported configuration

This commit is contained in:
2026-10-14 13:19:31 +00:00
parent 2f1f7f4b8a
commit a2fab66aba
4 changed files with 245 additions and 23 deletions

View File

@@ -45,10 +45,11 @@ type importAccounting struct {
}
type importTraversal struct {
access *filesystemAccess
accounting *importAccounting
limits importLimits
rule *VersionRule
access *filesystemAccess
accounting *importAccounting
limits importLimits
rule *VersionRule
destination Path
documents []*document.Node
sources []SourceInfo
@@ -58,16 +59,16 @@ type importTraversal struct {
}
func loadImportedDocuments(source Source, context *FilesystemContext, main parsedSource, rule *VersionRule, limits importLimits) (*composedDocument, []SourceInfo, []Diagnostic) {
return loadImportedDocumentsTracked(source, context, main, rule, limits, &importAccounting{}, nil, nil)
return loadImportedDocumentsTracked(source, context, main, Path{}, rule, limits, &importAccounting{}, nil, nil)
}
func loadImportedDocumentsTracked(source Source, context *FilesystemContext, main parsedSource, rule *VersionRule, limits importLimits, accounting *importAccounting, visited map[resourceIdentity]importRoute, hostToken *namespaceToken) (*composedDocument, []SourceInfo, []Diagnostic) {
func loadImportedDocumentsTracked(source Source, context *FilesystemContext, main parsedSource, destination Path, rule *VersionRule, limits importLimits, accounting *importAccounting, visited map[resourceIdentity]importRoute, hostToken *namespaceToken) (*composedDocument, []SourceInfo, []Diagnostic) {
if nativeContext(source, context) {
access, basePath, mainPath, diagnostic := nativeFilesystemAccess(source, context)
if diagnostic != nil {
return nil, sourceInfos(main.source), []Diagnostic{*diagnostic}
}
return loadImportedWithAccessTracked(access, basePath, mainPath, main, rule, limits, accounting, visited)
return loadImportedWithAccessTracked(access, basePath, mainPath, main, destination, rule, limits, accounting, visited)
}
rootPath, basePath, mainPath, diagnostic := importFilesystem(source, context, main)
if diagnostic != nil {
@@ -82,14 +83,14 @@ func loadImportedDocumentsTracked(source Source, context *FilesystemContext, mai
if hostToken != nil {
access.token = hostToken
}
return loadImportedWithAccessTracked(access, basePath, mainPath, main, rule, limits, accounting, visited)
return loadImportedWithAccessTracked(access, basePath, mainPath, main, destination, rule, limits, accounting, visited)
}
func loadImportedWithAccess(access *filesystemAccess, basePath, mainPath string, main parsedSource, rule *VersionRule, limits importLimits, accounting *importAccounting) (*composedDocument, []SourceInfo, []Diagnostic) {
return loadImportedWithAccessTracked(access, basePath, mainPath, main, rule, limits, accounting, nil)
return loadImportedWithAccessTracked(access, basePath, mainPath, main, Path{}, rule, limits, accounting, nil)
}
func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath string, main parsedSource, rule *VersionRule, limits importLimits, accounting *importAccounting, visited map[resourceIdentity]importRoute) (*composedDocument, []SourceInfo, []Diagnostic) {
func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath string, main parsedSource, destination Path, rule *VersionRule, limits importLimits, accounting *importAccounting, visited map[resourceIdentity]importRoute) (*composedDocument, []SourceInfo, []Diagnostic) {
if !access.contains(basePath) || (mainPath != "" && !access.contains(mainPath)) {
_ = access.close()
return nil, sourceInfos(main.source), []Diagnostic{importDiagnostic(CodeImportOutsideRoot, "selected source and import base must stay inside the configuration root", nil)}
@@ -102,6 +103,7 @@ func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath
}
}
mainInfo := cloneSourceInfo(*main.source)
mainInfo.Destination = destination.clone()
if mainPath != "" {
mainInfo.Path = mainPath
}
@@ -118,9 +120,10 @@ func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath
accounting.nodes += countInputNodes(main.document)
state := importTraversal{
access: access, accounting: accounting, limits: limits, rule: rule,
documents: make([]*document.Node, 0, 1),
sources: []SourceInfo{mainInfo},
active: make(map[resourceIdentity]int), visited: visited,
destination: destination.clone(),
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)
@@ -140,8 +143,13 @@ func loadImportedWithAccessTracked(access *filesystemAccess, basePath, mainPath
state.stack = append(state.stack, mainRoute)
body, declarations, diagnostics := splitImportDirectives(main.document)
if len(diagnostics) == 0 {
state.documents = append(state.documents, body)
diagnostics = state.walkDeclarations(basePath, declarations, 0)
_, placed, err := placeDocument(body, state.destination, body.Location, maxDocumentDepth, maxDocumentNodes)
if err != nil {
diagnostics = []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, main.source.ID, "configuration exceeds the source depth or node limit after destination placement")}
} else {
state.documents = append(state.documents, placed)
diagnostics = state.walkDeclarations(basePath, declarations, 0)
}
}
closeErr := access.close()
@@ -260,7 +268,7 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati
kind = SourceKindFilesystem
label = s.access.label + "/" + canonical
}
info := SourceInfo{ID: sourceID, Label: label, Path: canonical, Layer: LayerBase, Kind: kind, ImportedFrom: &location}
info := SourceInfo{ID: sourceID, Label: label, Path: canonical, Destination: s.destination.clone(), Layer: LayerBase, Kind: kind, ImportedFrom: &location}
if kind == SourceKindFilesystem {
info.namespace = s.access.token
}
@@ -291,7 +299,11 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati
if len(diagnostics) != 0 {
return diagnostics
}
if versionNode := fragmentVersionClaim(body, s.rule); versionNode != nil {
_, placed, err := placeDocument(body, s.destination, body.Location, maxDocumentDepth, maxDocumentNodes)
if err != nil {
return []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the source depth or node limit after destination placement", &location)}
}
if versionNode := fragmentVersionClaim(placed, s.rule); versionNode != nil {
versionLocation := publicLocation(versionNode.Location)
return []Diagnostic{{
Code: CodeImportVersion, Severity: SeverityError, Path: s.rule.Path.clone(),
@@ -300,7 +312,7 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati
}
route := importRoute{canonical: canonical, locations: currentRoute.locations}
s.documents = append(s.documents, body)
s.documents = append(s.documents, placed)
s.active[identity] = len(s.stack)
s.visited[identity] = route
s.stack = append(s.stack, route)