Consolidate selected overlay acquisition

This commit is contained in:
2026-10-25 13:18:54 +00:00
parent 9a64a65b6c
commit b915dd776a
9 changed files with 138 additions and 193 deletions

View File

@@ -1,6 +1,6 @@
# Consolidation Implementation Plan # Consolidation Implementation Plan
Status: in progress. Stages 1 through 8 are complete; follow Stage 9 through Stage 20 in order. Status: in progress. Stages 1 through 9 are complete; follow Stage 10 through Stage 20 in order.
The target executor is a Luna coding agent working through one end-to-end sprint. The target executor is a Luna coding agent working through one end-to-end sprint.
## Authority, Baseline, And Execution ## Authority, Baseline, And Execution
@@ -413,7 +413,7 @@ sources. Migrated the ordinary backfill and reordered-source context test. The
selected-overlay adapters remain for Stage 9. Focused context/acquisition tests, selected-overlay adapters remain for Stage 9. Focused context/acquisition tests,
`GOTOOLCHAIN=local GOPROXY=off go test ./...`, and `git diff --check` passed. `GOTOOLCHAIN=local GOPROXY=off go test ./...`, and `git diff --check` passed.
## Stage 9 — Migrate Selected Overlays Without Merging Their Semantics ## Stage 9 — Migrate Selected Overlays Without Merging Their Semantics (Complete)
**Owners:** engine `selected_overlay.go`, ordinary `applyInputLayers`, and **Owners:** engine `selected_overlay.go`, ordinary `applyInputLayers`, and
`assembleLayeredInput`. `assembleLayeredInput`.
@@ -445,6 +445,14 @@ ordinary and independent layered overlay semantics remain distinct. Run A when
buildable; carry any genuine remaining migration dependencies to the next buildable; carry any genuine remaining migration dependencies to the next
integration opportunity instead of adding scaffolding or stopping the sprint. integration opportunity instead of adding scaffolding or stopping the sprint.
Progress notes (2026-10-25): introduced the named overlay request and migrated
ordinary and independent layered overlay acquisition to resolved facts plus
explicit access. Replaced the variadic compatibility branch with the existing
collection-aware path, removed old context adapters, and retained overlay
validation timing, source evidence, budgets, version protection, and close
reporting. Validation group A, consumer examples, the full Go suite, and
`git diff --check` passed.
## Stage 10 — Give Import Responsibilities Focused Files ## Stage 10 — Give Import Responsibilities Focused Files
**Owners:** engine `imports.go` and new `import_acquisition.go`, **Owners:** engine `imports.go` and new `import_acquisition.go`,

View File

@@ -12,17 +12,20 @@ func validateFilesystemContext(source Source, context *FilesystemContext, main p
return validateAbsentHostFilesystemContext(context) return validateAbsentHostFilesystemContext(context)
} }
if nativeContext(source, context) { if nativeContext(source, context) {
access, basePath, mainPath, diagnostic := nativeFilesystemAccess(source, context) resolved, diagnostic := resolveNativeFilesystemContext(source, context)
if diagnostic != nil { if diagnostic != nil {
return diagnostic return diagnostic
} }
return validateNativeDirectories(access, basePath, mainPath) return validateResolvedFilesystemDirectories(resolved)
} }
rootPath, _, _, diagnostic := importFilesystem(source, context, main) resolved, diagnostic := resolveHostFilesystemContext(source, context, main, nil)
if diagnostic != nil { if diagnostic != nil {
return diagnostic return diagnostic
} }
root, err := os.OpenRoot(rootPath) if diagnostic := validateResolvedFilesystemDirectories(resolved); diagnostic != nil {
return diagnostic
}
root, err := os.OpenRoot(resolved.rootPath)
if err != nil { if err != nil {
value := globFilesystemDiagnostic(err, "configuration root could not be opened", Location{}) value := globFilesystemDiagnostic(err, "configuration root could not be opened", Location{})
value.Primary = nil value.Primary = nil
@@ -133,52 +136,6 @@ func nativeContext(source Source, context *FilesystemContext) bool {
return source.kind == sourceFilesystem || context != nil && context.FS != nil return source.kind == sourceFilesystem || context != nil && context.FS != nil
} }
// nativeFilesystemAccess resolves namespace context without opening caller
// resources. File inputs always derive their base from the selected file.
func nativeFilesystemAccess(source Source, context *FilesystemContext) (*filesystemAccess, string, string, *Diagnostic) {
resolved, diagnostic := resolveNativeFilesystemContext(source, context)
if diagnostic != nil {
return nil, "", "", diagnostic
}
access, err := openResolvedFilesystemAccess(resolved)
if err != nil {
value := globFilesystemDiagnostic(err, "configuration root could not be opened", Location{})
value.Primary = nil
return nil, "", "", &value
}
return access, resolved.basePath, resolved.mainPath, nil
}
func validateNativeDirectories(access *filesystemAccess, basePath, mainPath string) *Diagnostic {
if !access.contains(basePath) || mainPath != "" && !access.contains(mainPath) {
value := importDiagnostic(CodeImportOutsideRoot, "selected source and import base must stay inside the configuration root", nil)
return &value
}
for _, directory := range []string{access.rootPath, basePath} {
info, err := access.stat(directory)
if err != nil || !info.IsDir() {
value := importDiagnostic(CodeImportInvalid, "configuration root and import base must be directories", nil)
return &value
}
}
return nil
}
func importFilesystem(source Source, context *FilesystemContext, main parsedSource) (rootPath, basePath, mainPath string, diagnostic *Diagnostic) {
if main.source == nil || main.document == nil {
value := importDiagnostic(CodeImportInvalid, "imports require a selected configuration source", nil)
return "", "", "", &value
}
resolved, diagnostic := resolveHostFilesystemContext(source, context, main, nil)
if diagnostic != nil {
return "", "", "", diagnostic
}
if diagnostic := validateResolvedFilesystemDirectories(resolved); diagnostic != nil {
return "", "", "", diagnostic
}
return resolved.rootPath, resolved.basePath, resolved.mainPath, nil
}
func canonicalExistingPath(name string) (string, error) { func canonicalExistingPath(name string) (string, error) {
absolute, err := filepath.Abs(name) absolute, err := filepath.Abs(name)
if err != nil { if err != nil {

View File

@@ -43,6 +43,10 @@ func resolveAbsentFilesystemContext(context *FilesystemContext) (resolvedFilesys
return resolvedFilesystemContext{}, &value return resolvedFilesystemContext{}, &value
} }
} }
if !containedPath(rootPath, basePath) {
value := importDiagnostic(CodeImportOutsideRoot, "selected source and import base must stay inside the configuration root", nil)
return resolvedFilesystemContext{}, &value
}
return resolvedFilesystemContext{rootPath: rootPath, basePath: basePath}, nil return resolvedFilesystemContext{rootPath: rootPath, basePath: basePath}, nil
} }

View File

@@ -97,14 +97,29 @@ func applyInputLayers(source Source, filesystem *FilesystemContext, overlay stri
return input, diagnostics return input, diagnostics
} }
assembly := newAssemblyAccumulator(composition) assembly := newAssemblyAccumulator(composition)
input.sources, diagnostics = loadSelectedOverlayIntoWithVersion( resolved, diagnostic := resolveOrdinaryOverlayFilesystem(source, filesystem, input.parsed, input.resolvedFilesystem)
source, filesystem, input.parsed, assembly, input.sources, if diagnostic != nil {
overlay, protectionRule, defaultImportLimits(), input.versionState, policy, return input, []Diagnostic{*diagnostic}
) }
if source.kind != sourceNone || nativeContext(source, filesystem) {
if diagnostic := validateResolvedFilesystemDirectories(resolved); diagnostic != nil {
return input, []Diagnostic{*diagnostic}
}
}
request := selectedOverlayRequest{
name: overlay, filesystem: resolved, protectionRule: protectionRule,
sequencePolicy: policy, limits: defaultImportLimits(), versionState: input.versionState,
}
access, diagnostic := openSelectedOverlayAccess(resolved)
if diagnostic != nil {
return input, []Diagnostic{*diagnostic}
}
input.sources, diagnostics = loadSelectedOverlay(request, access, assembly, input.sources)
if len(diagnostics) != 0 { if len(diagnostics) != 0 {
return input, diagnostics return input, diagnostics
} }
contexts, diagnostic := contextsForAcquiredSources(source, filesystem, input.parsed.source, input.sources[len(input.sources)-1:]) input.resolvedFilesystem = &resolved
contexts, diagnostic := contextsForResolvedSources(&resolved, input.sources[len(input.sources)-1:])
if diagnostic != nil { if diagnostic != nil {
return input, []Diagnostic{*diagnostic} return input, []Diagnostic{*diagnostic}
} }

View File

@@ -192,17 +192,30 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, p
assembly.current.inputBytes = state.accounting.bytes assembly.current.inputBytes = state.accounting.bytes
assembly.current.inputNodes = state.accounting.nodes assembly.current.inputNodes = state.accounting.nodes
if activeOverlay(request.overlay) { if activeOverlay(request.overlay) {
// The selected overlay context is independent of the main input. This if request.overlayFilesystem == nil {
// synthetic descriptor creates no source record or input contribution. return input, append(versionDiagnostics, optionDiagnostic(CodeOptionsInvalid, "selected overlay requires explicit filesystem context"))
selection := Source{kind: sourceBytes} }
selected := parsedSource{document: &document.Node{Kind: document.Mapping}, source: &SourceInfo{}} resolved, diagnostic := resolveAbsentFilesystemContext(request.overlayFilesystem)
if diagnostic != nil {
return input, append(versionDiagnostics, *diagnostic)
}
if diagnostic := validateResolvedFilesystemDirectories(resolved); diagnostic != nil {
return input, append(versionDiagnostics, *diagnostic)
}
overlayRequest := selectedOverlayRequest{
name: request.overlay, filesystem: resolved, protectionRule: request.protectionVersion(),
sequencePolicy: policy.sequencePolicy, limits: defaultImportLimits(), versionState: input.versionState,
}
var diagnostics []Diagnostic var diagnostics []Diagnostic
overlayPolicy := []sequencePolicy{policy.sequencePolicy} access, diagnostic := openSelectedOverlayAccess(resolved)
input.sources, diagnostics = loadSelectedOverlayIntoWithVersion(selection, request.overlayFilesystem, selected, assembly, input.sources, request.overlay, request.protectionVersion(), defaultImportLimits(), input.versionState, overlayPolicy...) if diagnostic != nil {
return input, append(versionDiagnostics, *diagnostic)
}
input.sources, diagnostics = loadSelectedOverlay(overlayRequest, access, assembly, input.sources)
if len(diagnostics) != 0 { if len(diagnostics) != 0 {
return input, append(versionDiagnostics, diagnostics...) return input, append(versionDiagnostics, diagnostics...)
} }
contexts, diagnostic := contextsForAcquiredSources(selection, request.overlayFilesystem, selected.source, input.sources[len(input.sources)-1:]) contexts, diagnostic := contextsForResolvedSources(&resolved, input.sources[len(input.sources)-1:])
if diagnostic != nil { if diagnostic != nil {
return input, append(versionDiagnostics, *diagnostic) return input, append(versionDiagnostics, *diagnostic)
} }

View File

@@ -28,84 +28,51 @@ func validOverlayName(name string) bool {
return true return true
} }
func loadSelectedOverlayDocument(source Source, context *FilesystemContext, main parsedSource, base *composedDocument, sources []SourceInfo, name string, rule *VersionRule, limits importLimits) (*composedDocument, []SourceInfo, []Diagnostic) { type selectedOverlayRequest struct {
assembly := newAssemblyAccumulator(cloneComposedDocument(base)) name string
allSources, diagnostics := loadSelectedOverlayInto(source, context, main, assembly, sources, name, rule, limits) filesystem resolvedFilesystemContext
if len(diagnostics) != 0 { protectionRule *VersionRule
return nil, allSources, diagnostics sequencePolicy sequencePolicy
} limits importLimits
return assembly.current, allSources, nil versionState *sourceVersionState
} }
func loadSelectedOverlayInto(source Source, context *FilesystemContext, main parsedSource, base *assemblyAccumulator, sources []SourceInfo, name string, rule *VersionRule, limits importLimits) ([]SourceInfo, []Diagnostic) { func resolveOrdinaryOverlayFilesystem(source Source, context *FilesystemContext, main parsedSource, existing *resolvedFilesystemContext) (resolvedFilesystemContext, *Diagnostic) {
return loadSelectedOverlayIntoWithVersion(source, context, main, base, sources, name, rule, limits, nil)
}
func loadSelectedOverlayIntoWithVersion(source Source, context *FilesystemContext, main parsedSource, base *assemblyAccumulator, sources []SourceInfo, name string, rule *VersionRule, limits importLimits, versionState *sourceVersionState, policies ...sequencePolicy) ([]SourceInfo, []Diagnostic) {
var policy sequencePolicy
if len(policies) != 0 {
policy = policies[0]
}
if nativeContext(source, context) {
access, basePath, mainPath, diagnostic := nativeFilesystemAccess(source, context)
if diagnostic != nil {
return cloneSourceInfos(sources), []Diagnostic{*diagnostic}
}
if diagnostic := validateNativeDirectories(access, basePath, mainPath); diagnostic != nil {
return cloneSourceInfos(sources), []Diagnostic{*diagnostic}
}
if len(policies) == 0 {
return loadSelectedOverlayWithAccessAndVersion(access, base, sources, name, rule, limits, versionState)
}
return loadSelectedOverlayWithAccessAndVersion(access, base, sources, name, rule, limits, versionState, policy)
}
var rootPath string
if source.kind == sourceNone { if source.kind == sourceNone {
if context == nil { if context == nil {
value := optionDiagnostic(CodeOptionsInvalid, "NoSource overlays require explicit filesystem context") value := optionDiagnostic(CodeOptionsInvalid, "NoSource overlays require explicit filesystem context")
return cloneSourceInfos(sources), []Diagnostic{value} return resolvedFilesystemContext{}, &value
}
var err error
rootPath, err = canonicalExistingPath(context.Root)
if err != nil {
value := importDiagnostic(CodeImportInvalid, "configuration root could not be canonicalized", nil)
return cloneSourceInfos(sources), []Diagnostic{value}
}
} else {
var diagnostic *Diagnostic
rootPath, _, _, diagnostic = importFilesystem(source, context, main)
if diagnostic != nil {
return cloneSourceInfos(sources), []Diagnostic{*diagnostic}
} }
return resolveAbsentFilesystemContext(context)
} }
access, err := openHostAccess(rootPath) if existing != nil {
return *existing, nil
}
return resolveFilesystemContext(source, context, main, nil)
}
func openSelectedOverlayAccess(resolved resolvedFilesystemContext) (*filesystemAccess, *Diagnostic) {
access, err := openResolvedFilesystemAccess(resolved)
if err != nil { if err != nil {
value := globFilesystemDiagnostic(err, "configuration root could not be opened for the selected overlay", Location{}) value := globFilesystemDiagnostic(err, "configuration root could not be opened for the selected overlay", Location{})
value.Primary = nil value.Primary = nil
return cloneSourceInfos(sources), []Diagnostic{value} return nil, &value
} }
if len(policies) == 0 { return access, nil
return loadSelectedOverlayWithAccessAndVersion(access, base, sources, name, rule, limits, versionState)
}
return loadSelectedOverlayWithAccessAndVersion(access, base, sources, name, rule, limits, versionState, policy)
} }
func loadSelectedOverlayWithAccess(access *filesystemAccess, base *assemblyAccumulator, sources []SourceInfo, name string, rule *VersionRule, limits importLimits) ([]SourceInfo, []Diagnostic) { func loadSelectedOverlay(request selectedOverlayRequest, access *filesystemAccess, base *assemblyAccumulator, sources []SourceInfo) ([]SourceInfo, []Diagnostic) {
return loadSelectedOverlayWithAccessAndVersion(access, base, sources, name, rule, limits, nil) policy := request.sequencePolicy
} rule := request.protectionRule
limits := request.limits
func loadSelectedOverlayWithAccessAndVersion(access *filesystemAccess, base *assemblyAccumulator, sources []SourceInfo, name string, rule *VersionRule, limits importLimits, versionState *sourceVersionState, policies ...sequencePolicy) ([]SourceInfo, []Diagnostic) { versionState := request.versionState
var policy sequencePolicy
if len(policies) != 0 {
policy = policies[0]
}
closed := false closed := false
defer func() { defer func() {
if !closed { if !closed {
_ = access.close() _ = access.close()
} }
}() }()
overlayPath := access.join(access.rootPath, "overlays/"+name+".yml") overlayPath := access.join(access.rootPath, "overlays/"+request.name+".yml")
canonical, err := access.canonical(overlayPath) canonical, err := access.canonical(overlayPath)
if err != nil { if err != nil {
code := CodeOverlayInvalid code := CodeOverlayInvalid
@@ -138,7 +105,7 @@ func loadSelectedOverlayWithAccessAndVersion(access *filesystemAccess, base *ass
sourceID := "source-" + strconv.Itoa(len(sources)+1) sourceID := "source-" + strconv.Itoa(len(sources)+1)
overlayLocation := &Location{SourceID: sourceID} overlayLocation := &Location{SourceID: sourceID}
kind := SourceKindFile kind := SourceKindFile
label := "overlays/" + name + ".yml" label := "overlays/" + request.name + ".yml"
if access.native != nil { if access.native != nil {
kind = SourceKindFilesystem kind = SourceKindFilesystem
label = access.label + "/" + canonical label = access.label + "/" + canonical
@@ -160,66 +127,44 @@ func loadSelectedOverlayWithAccessAndVersion(access *filesystemAccess, base *ass
if base.current.inputNodes+nodeCount > limits.nodes { if base.current.inputNodes+nodeCount > limits.nodes {
return sources, []Diagnostic{importDiagnostic(CodeOverlayLimitExceeded, "selected overlay exceeds the aggregate node limit", overlayLocation)} return sources, []Diagnostic{importDiagnostic(CodeOverlayLimitExceeded, "selected overlay exceeds the aggregate node limit", overlayLocation)}
} }
if diagnostics := overlayDirectiveDiagnostics(overlayRoot, Path{}, len(policies) != 0); len(diagnostics) != 0 { if diagnostics := overlayDirectiveDiagnostics(overlayRoot, Path{}, true); len(diagnostics) != 0 {
return sources, diagnostics return sources, diagnostics
} }
var processed sourceVersionProcessingResult var processed sourceVersionProcessingResult
var failures []Diagnostic var failures []Diagnostic
if len(policies) != 0 { if versionState != nil {
if versionState != nil { processed, failures = versionState.processWithDirectiveContext(
processed, failures = versionState.processWithDirectiveContext( overlayRoot, sourceVersionContribution, Path{}, sourceID, placementModeMapping, rootDirectiveContextOverlay,
overlayRoot, sourceVersionContribution, Path{}, sourceID, placementModeMapping, rootDirectiveContextOverlay, )
)
} else {
processed = processSourceVersionWithDirectiveContext(
overlayRoot, rule, sourceVersionContribution, Path{}, sourceVersionModeDefault, rootDirectiveContextOverlay,
)
failures = processed.diagnostics
}
} else { } else {
if versionState != nil && versionState.mode != sourceVersionModeDefault { processed = processSourceVersionWithDirectiveContext(
processed, failures = versionState.process(overlayRoot, sourceVersionContribution, Path{}, sourceID, placementModeMapping) overlayRoot, rule, sourceVersionContribution, Path{}, sourceVersionModeDefault, rootDirectiveContextOverlay,
} else { )
processed = sourceVersionProcessingResult{payload: overlayRoot} failures = processed.diagnostics
}
} }
if len(failures) != 0 { if len(failures) != 0 {
return sources, failures return sources, failures
} }
overlayPayload := processed.payload overlayPayload := processed.payload
if versionNode := fragmentVersionClaim(overlayPayload, rule); len(policies) == 0 && versionNode != nil {
location := publicLocation(versionNode.Location)
return sources, []Diagnostic{{
Code: CodeOverlayVersion, Severity: SeverityError, Path: rule.Path.clone(),
Message: "overlays cannot contribute to or replace the schema-version path", Primary: &location,
}}
}
closeErr := access.close() closeErr := access.close()
closed = true closed = true
if closeErr != nil { if closeErr != nil {
return sources, []Diagnostic{importDiagnostic(CodeImportRead, "configuration root could not be closed after reading the selected overlay", nil)} return sources, []Diagnostic{importDiagnostic(CodeImportRead, "configuration root could not be closed after reading the selected overlay", nil)}
} }
var overlayDiagnostics []Diagnostic overlayDiagnostics := base.applyOverlayWithCollectionPolicy(overlayPayload, nil, collectionPolicyScope{}, nil, LayerOverlay, policy, processed.sequences)
if len(policies) != 0 {
overlayDiagnostics = base.applyOverlayWithCollectionPolicy(overlayPayload, nil, collectionPolicyScope{}, nil, LayerOverlay, policy, processed.sequences)
} else {
overlayDiagnostics = base.applyOverlay(overlayPayload, nil, nil, LayerOverlay)
}
if len(overlayDiagnostics) != 0 { if len(overlayDiagnostics) != 0 {
return sources, overlayDiagnostics return sources, overlayDiagnostics
} }
if len(policies) != 0 { // The selected overlay retains one application with the actual item
// The selected overlay retains one application with the actual item // assignments. Raw list indexes cannot identify an upsert's destination.
// assignments. Raw list indexes cannot identify an upsert's destination. application := base.current.applications[len(base.current.applications)-1]
application := base.current.applications[len(base.current.applications)-1] if node := versionClaimFromApplication(application, rule); node != nil {
if node := versionClaimFromApplication(application, rule); node != nil { location := publicLocation(node.Location)
location := publicLocation(node.Location) return sources, []Diagnostic{{
return sources, []Diagnostic{{ Code: CodeOverlayVersion, Severity: SeverityError, Path: rule.Path.clone(),
Code: CodeOverlayVersion, Severity: SeverityError, Path: rule.Path.clone(), Message: "overlays cannot contribute to or replace the schema-version path", Primary: &location,
Message: "overlays cannot contribute to or replace the schema-version path", Primary: &location, }}
}}
}
} }
base.current.inputBytes += int64(len(data)) base.current.inputBytes += int64(len(data))
base.current.inputNodes += nodeCount base.current.inputNodes += nodeCount

View File

@@ -585,7 +585,21 @@ func TestLoadOverlayCountsAgainstAggregateBudgets(t *testing.T) {
} }
base.inputBytes = main.bytes base.inputBytes = main.bytes
base.inputNodes = countInputNodes(main.document) base.inputNodes = countInputNodes(main.document)
_, _, diagnostics = loadSelectedOverlayDocument(File(mainPath), nil, main, base, sourceInfos(main.source), "testing", nil, test.limits(main, len(overlayData))) resolved, diagnostic := resolveFilesystemContext(File(mainPath), nil, main, nil)
if diagnostic != nil {
t.Fatal(diagnostic)
}
request := selectedOverlayRequest{
name: "testing", filesystem: resolved, limits: test.limits(main, len(overlayData)),
}
if diagnostic := validateResolvedFilesystemDirectories(resolved); diagnostic != nil {
t.Fatal(diagnostic)
}
access, diagnostic := openSelectedOverlayAccess(resolved)
if diagnostic != nil {
t.Fatal(diagnostic)
}
_, diagnostics = loadSelectedOverlay(request, access, newAssemblyAccumulator(base), sourceInfos(main.source))
if len(diagnostics) == 0 || diagnostics[0].Code != CodeOverlayLimitExceeded { if len(diagnostics) == 0 || diagnostics[0].Code != CodeOverlayLimitExceeded {
t.Fatalf("diagnostics = %#v", diagnostics) t.Fatalf("diagnostics = %#v", diagnostics)
} }

View File

@@ -66,30 +66,6 @@ func contextsForResolvedSources(resolved *resolvedFilesystemContext, sources []S
return result, nil return result, nil
} }
// contextsForAcquiredSources is retained for selected-overlay callers until
// their request migration. Input acquisition resolves the facts at its own
// lifecycle boundary and uses contextsForResolvedSources directly.
func contextsForAcquiredSources(source Source, context *FilesystemContext, baseSource *SourceInfo, sources []SourceInfo) (map[string]ResourceContext, *Diagnostic) {
if len(sources) == 0 {
return nil, nil
}
if source.kind == sourceNone {
if context == nil {
return nil, nil
}
resolved, diagnostic := resolveAbsentFilesystemContext(context)
if diagnostic != nil {
return nil, diagnostic
}
return contextsForResolvedSources(&resolved, sources)
}
resolved, diagnostic := resolveFilesystemContext(source, context, parsedSource{source: baseSource}, nil)
if diagnostic != nil {
return nil, diagnostic
}
return contextsForResolvedSources(&resolved, sources)
}
func mergeResourceContexts(target *map[string]ResourceContext, incoming map[string]ResourceContext) { func mergeResourceContexts(target *map[string]ResourceContext, incoming map[string]ResourceContext) {
if len(incoming) == 0 { if len(incoming) == 0 {
return return

View File

@@ -1487,9 +1487,22 @@ func TestSourceVersionOverlayProtectsMountedMainAndPreservesSequenceCoordinates(
t.Fatalf("compose base: %#v", compositionDiagnostics) t.Fatalf("compose base: %#v", compositionDiagnostics)
} }
assembly := newAssemblyAccumulator(base) assembly := newAssemblyAccumulator(base)
_, diagnostics = loadSelectedOverlayIntoWithVersion( resolved, diagnostic := resolveFilesystemContext(File(mainPath), nil, main, nil)
File(mainPath), nil, main, assembly, sourceInfos(main.source), "testing", effectiveRule, defaultImportLimits(), state, if diagnostic != nil {
) t.Fatalf("resolve overlay context: %#v", diagnostic)
}
request := selectedOverlayRequest{
name: "testing", filesystem: resolved, protectionRule: effectiveRule,
limits: defaultImportLimits(), versionState: state,
}
if diagnostic := validateResolvedFilesystemDirectories(resolved); diagnostic != nil {
t.Fatalf("validate overlay context: %#v", diagnostic)
}
access, diagnostic := openSelectedOverlayAccess(resolved)
if diagnostic != nil {
t.Fatalf("open overlay context: %#v", diagnostic)
}
_, diagnostics = loadSelectedOverlay(request, access, assembly, sourceInfos(main.source))
if len(diagnostics) != 0 { if len(diagnostics) != 0 {
t.Fatalf("load selected overlay: %#v", diagnostics) t.Fatalf("load selected overlay: %#v", diagnostics)
} }