Construct placement directly across the facade
This commit is contained in:
@@ -204,7 +204,8 @@ Focused checks:
|
||||
|
||||
Finding: **F07**, placement handoff. Owners: engine `destination.go`, `load.go`,
|
||||
`layered.go`, normalized input and placement consumers; root `lifecycle.go`,
|
||||
`layered.go`, and placement fixtures. Status: **not started**.
|
||||
`layered.go`, and placement fixtures. Status: **complete**. Validation passed:
|
||||
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -run 'Destination|Placement|Item|SourceVersion'`, `env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test . -run 'Placement|Destination|SourceInfo|SourceVersion|PublicFacadeBoundary|DependencyImportBoundary'`, `env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./...`, and `git diff --check`.
|
||||
|
||||
1. Rename the existing engine enum and its constants to `PlacementMode`,
|
||||
`PlacementModeMapping`, and `PlacementModeSequenceItem`, preserving underlying
|
||||
|
||||
@@ -11,26 +11,13 @@ var (
|
||||
errDestinationLimit = errors.New("configkit: destination exceeds document limits")
|
||||
)
|
||||
|
||||
type placementMode uint8
|
||||
type PlacementMode uint8
|
||||
|
||||
const (
|
||||
placementModeMapping placementMode = iota
|
||||
placementModeSequenceItem
|
||||
PlacementModeMapping PlacementMode = iota
|
||||
PlacementModeSequenceItem
|
||||
)
|
||||
|
||||
// InputWithPlacement copies the root-owned mode into a private engine input.
|
||||
func InputWithPlacement(input Input, value uint8) Input {
|
||||
input.placementMode = placementMode(value)
|
||||
return input
|
||||
}
|
||||
|
||||
// OptionsWithPlacement copies root-owned controls into private engine options.
|
||||
func OptionsWithPlacement[T any](options Options[T], destination Path, value uint8) Options[T] {
|
||||
options.destination = destination.clone()
|
||||
options.placementMode = placementMode(value)
|
||||
return options
|
||||
}
|
||||
|
||||
func normalizeDestination(path Path) (Path, error) {
|
||||
if !path.valid() {
|
||||
return Path{}, errInvalidDestination
|
||||
@@ -67,26 +54,26 @@ func invalidDestinationDiagnostic(destination Path) Diagnostic {
|
||||
// placeDocument checks all per-document bounds before allocating destination
|
||||
// wrappers. Aggregate accounting remains the caller's responsibility.
|
||||
func placeDocument(body *document.Node, destination Path, sourceRoot document.Location, maxDepth, maxNodes int) (Path, *document.Node, error) {
|
||||
return placeDocumentWithMode(body, destination, placementModeMapping, sourceRoot, maxDepth, maxNodes)
|
||||
return placeDocumentWithMode(body, destination, PlacementModeMapping, sourceRoot, maxDepth, maxNodes)
|
||||
}
|
||||
|
||||
// placeDocumentWithMode places a source mapping beneath its literal destination.
|
||||
// Sequence-item placement adds one sequence containing the complete mapping.
|
||||
func placeDocumentWithMode(body *document.Node, destination Path, mode placementMode, sourceRoot document.Location, maxDepth, maxNodes int) (Path, *document.Node, error) {
|
||||
func placeDocumentWithMode(body *document.Node, destination Path, mode PlacementMode, sourceRoot document.Location, maxDepth, maxNodes int) (Path, *document.Node, error) {
|
||||
normalized, err := normalizeDestination(destination)
|
||||
if err != nil {
|
||||
return Path{}, nil, err
|
||||
}
|
||||
if mode != placementModeMapping && mode != placementModeSequenceItem {
|
||||
if mode != PlacementModeMapping && mode != PlacementModeSequenceItem {
|
||||
return Path{}, nil, errInvalidDestination
|
||||
}
|
||||
if mode == placementModeSequenceItem && len(normalized.segments) == 0 {
|
||||
if mode == PlacementModeSequenceItem && len(normalized.segments) == 0 {
|
||||
return Path{}, nil, errInvalidDestination
|
||||
}
|
||||
if body == nil {
|
||||
return normalized, nil, nil
|
||||
}
|
||||
if mode == placementModeSequenceItem && body.Kind != document.Mapping {
|
||||
if mode == PlacementModeSequenceItem && body.Kind != document.Mapping {
|
||||
return normalized, nil, errInvalidDestination
|
||||
}
|
||||
if !destinationWithinLimitsWithMode(body, normalized, mode, maxDepth, maxNodes) {
|
||||
@@ -94,7 +81,7 @@ func placeDocumentWithMode(body *document.Node, destination Path, mode placement
|
||||
}
|
||||
|
||||
placed := body
|
||||
if mode == placementModeSequenceItem {
|
||||
if mode == PlacementModeSequenceItem {
|
||||
placed = &document.Node{
|
||||
Kind: document.Sequence, Location: sourceRoot,
|
||||
Sequence: []*document.Node{placed},
|
||||
@@ -118,20 +105,20 @@ func placeDocumentWithMode(body *document.Node, destination Path, mode placement
|
||||
|
||||
// destinationWithinLimits expects a normalized mapping-key destination.
|
||||
func destinationWithinLimits(body *document.Node, destination Path, maxDepth, maxNodes int) bool {
|
||||
return destinationWithinLimitsWithMode(body, destination, placementModeMapping, maxDepth, maxNodes)
|
||||
return destinationWithinLimitsWithMode(body, destination, PlacementModeMapping, maxDepth, maxNodes)
|
||||
}
|
||||
|
||||
func destinationWithinLimitsWithMode(body *document.Node, destination Path, mode placementMode, maxDepth, maxNodes int) bool {
|
||||
func destinationWithinLimitsWithMode(body *document.Node, destination Path, mode PlacementMode, maxDepth, maxNodes int) bool {
|
||||
if body == nil {
|
||||
return true
|
||||
}
|
||||
if maxDepth < 0 || maxNodes < 0 || !destination.valid() || (mode != placementModeMapping && mode != placementModeSequenceItem) {
|
||||
if maxDepth < 0 || maxNodes < 0 || !destination.valid() || (mode != PlacementModeMapping && mode != PlacementModeSequenceItem) {
|
||||
return false
|
||||
}
|
||||
segments := len(destination.segments)
|
||||
sequenceNodes := 0
|
||||
sequenceDepth := 0
|
||||
if mode == placementModeSequenceItem {
|
||||
if mode == PlacementModeSequenceItem {
|
||||
if segments == 0 {
|
||||
return false
|
||||
}
|
||||
@@ -153,9 +140,9 @@ func destinationWithinLimitsWithMode(body *document.Node, destination Path, mode
|
||||
return countInputNodes(body) <= maxNodes-wrapperNodes
|
||||
}
|
||||
|
||||
func destinationWrapperNodeCountForMode(destination Path, mode placementMode) int {
|
||||
func destinationWrapperNodeCountForMode(destination Path, mode PlacementMode) int {
|
||||
count := destinationWrapperNodeCount(destination)
|
||||
if mode == placementModeSequenceItem {
|
||||
if mode == PlacementModeSequenceItem {
|
||||
count++
|
||||
}
|
||||
return count
|
||||
|
||||
@@ -92,9 +92,9 @@ id: parent
|
||||
childDestination := appendDestination(destination, Keys("children"))
|
||||
otherDestination := Keys("other")
|
||||
wantNodes := parseNodes(mainPath) + parseNodes(fragmentPath) + countInputNodes(&document.Node{Kind: document.Mapping}) +
|
||||
destinationWrapperNodeCountForMode(destination, placementModeSequenceItem) +
|
||||
destinationWrapperNodeCountForMode(childDestination, placementModeSequenceItem) +
|
||||
destinationWrapperNodeCountForMode(otherDestination, placementModeSequenceItem)
|
||||
destinationWrapperNodeCountForMode(destination, PlacementModeSequenceItem) +
|
||||
destinationWrapperNodeCountForMode(childDestination, PlacementModeSequenceItem) +
|
||||
destinationWrapperNodeCountForMode(otherDestination, PlacementModeSequenceItem)
|
||||
limits := defaultImportLimits()
|
||||
|
||||
for _, test := range []struct {
|
||||
@@ -108,9 +108,9 @@ id: parent
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
accounting := &importAccounting{nodes: limits.nodes - wantNodes + test.delta}
|
||||
acquired, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{
|
||||
source: File(mainPath), imports: true, destination: destination, placementMode: placementModeSequenceItem,
|
||||
source: File(mainPath), imports: true, destination: destination, placementMode: PlacementModeSequenceItem,
|
||||
}, {
|
||||
source: Mapping("other", map[string]any{"id": "other"}), destination: otherDestination, placementMode: placementModeSequenceItem,
|
||||
source: Mapping("other", map[string]any{"id": "other"}), destination: otherDestination, placementMode: PlacementModeSequenceItem,
|
||||
}}}, 1, nil, accounting)
|
||||
if test.wantError {
|
||||
if len(diagnostics) == 0 || diagnostics[0].Code != CodeSourceLimitExceeded {
|
||||
|
||||
@@ -201,7 +201,7 @@ func TestLayeredItemVersionProtectionTracksAssignedPeerIndexes(t *testing.T) {
|
||||
sequenceIdentityRegistrations: []sequenceIdentityRegistration{{selector: sequenceIdentitySelector{literalSequenceSelector("catalog"), literalSequenceSelector("entries")}, identityFields: []string{"id"}}},
|
||||
}
|
||||
item := func(label string, value map[string]any) Input {
|
||||
return Input{Source: Mapping(label, value), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem}
|
||||
return Input{Source: Mapping(label, value), Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem}
|
||||
}
|
||||
options := func(inputs ...Input) LayeredOptions[map[string]any] {
|
||||
return LayeredOptions[map[string]any]{Definition: definition, SourceVersionMode: sourceVersionModeIfPresent, Underlays: []Underlay{{Inputs: inputs}}}
|
||||
|
||||
@@ -22,11 +22,11 @@ func TestLayeredLoadPlacesCompletedMappingAsOneItem(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
loaded, err := LoadLayered[destinationItemConfig](
|
||||
Input{Source: NoSource(), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem},
|
||||
Input{Source: NoSource(), Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem},
|
||||
testSecretBinding(),
|
||||
LayeredOptions[destinationItemConfig]{Underlays: []Underlay{{Inputs: []Input{{
|
||||
Source: Mapping("empty-item", map[string]any{}), Destination: Keys("catalog", "entries"),
|
||||
placementMode: placementModeSequenceItem,
|
||||
PlacementMode: PlacementModeSequenceItem,
|
||||
}}}}},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -40,7 +40,7 @@ func TestLayeredLoadPlacesCompletedMappingAsOneItem(t *testing.T) {
|
||||
t.Fatal("sequence index was treated as a literal mapping key during metadata lookup")
|
||||
}
|
||||
sources := result.Sources()
|
||||
if len(sources) != 1 || sources[0].placementMode != placementModeSequenceItem || sources[0].destinationUnresolved {
|
||||
if len(sources) != 1 || sources[0].placementMode != PlacementModeSequenceItem || sources[0].destinationUnresolved {
|
||||
t.Fatalf("source placement evidence = %#v", sources)
|
||||
}
|
||||
if got := sources[0].Destination.String(); got != "/catalog/entries" {
|
||||
@@ -48,7 +48,7 @@ func TestLayeredLoadPlacesCompletedMappingAsOneItem(t *testing.T) {
|
||||
}
|
||||
|
||||
absent, err := LoadLayered[destinationItemConfig](
|
||||
Input{Source: NoSource(), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem},
|
||||
Input{Source: NoSource(), Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem},
|
||||
testSecretBinding(),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -64,17 +64,17 @@ func TestLayeredItemPlacementPreflightsModeAndDestination(t *testing.T) {
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
mode placementMode
|
||||
mode PlacementMode
|
||||
path Path
|
||||
}{
|
||||
{name: "root item", mode: placementModeSequenceItem},
|
||||
{name: "unknown mode", mode: placementMode(255), path: Keys("catalog")},
|
||||
{name: "root item", mode: PlacementModeSequenceItem},
|
||||
{name: "unknown mode", mode: PlacementMode(255), path: Keys("catalog")},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
reader := bytes.NewBufferString("value: unused\n")
|
||||
_, err := LoadLayered[destinationItemConfig](
|
||||
Input{Source: Reader("reader", reader), Destination: test.path, placementMode: test.mode},
|
||||
Input{Source: Reader("reader", reader), Destination: test.path, PlacementMode: test.mode},
|
||||
testSecretBinding(),
|
||||
)
|
||||
if err == nil || reader.Len() == 0 {
|
||||
@@ -93,7 +93,7 @@ func TestLoadOptionsPlaceOneMappingItem(t *testing.T) {
|
||||
|
||||
loaded, err := Load[destinationItemConfig](
|
||||
Mapping("ordinary", map[string]any{}), testSecretBinding(),
|
||||
Options[destinationItemConfig]{destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem},
|
||||
Options[destinationItemConfig]{Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestMappingPlacementModeMatchesZeroValue(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
explicitPath, explicit, err := placeDocumentWithMode(body, destination, placementModeMapping, body.Location, 5, 32)
|
||||
explicitPath, explicit, err := placeDocumentWithMode(body, destination, PlacementModeMapping, body.Location, 5, 32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -235,7 +235,7 @@ func TestPlaceDocumentSequenceItemAndMountedBounds(t *testing.T) {
|
||||
root := document.Location{SourceID: "item", Line: 1, Column: 1}
|
||||
body := &document.Node{Kind: document.Mapping, Location: root}
|
||||
destination := Keys("catalog", "entries")
|
||||
placedPath, placed, err := placeDocumentWithMode(body, destination, placementModeSequenceItem, root, 3, 6)
|
||||
placedPath, placed, err := placeDocumentWithMode(body, destination, PlacementModeSequenceItem, root, 3, 6)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -253,13 +253,13 @@ func TestPlaceDocumentSequenceItemAndMountedBounds(t *testing.T) {
|
||||
t.Fatal("synthetic sequence or authored mapping lost source coordinates")
|
||||
}
|
||||
|
||||
if _, _, err := placeDocumentWithMode(body, Path{}, placementModeSequenceItem, root, 3, 6); !errors.Is(err, errInvalidDestination) {
|
||||
if _, _, err := placeDocumentWithMode(body, Path{}, PlacementModeSequenceItem, root, 3, 6); !errors.Is(err, errInvalidDestination) {
|
||||
t.Fatalf("root item placement error = %v, want invalid destination", err)
|
||||
}
|
||||
if _, _, err := placeDocumentWithMode(&document.Node{Kind: document.String}, destination, placementModeSequenceItem, root, 3, 6); !errors.Is(err, errInvalidDestination) {
|
||||
if _, _, err := placeDocumentWithMode(&document.Node{Kind: document.String}, destination, PlacementModeSequenceItem, root, 3, 6); !errors.Is(err, errInvalidDestination) {
|
||||
t.Fatalf("non-mapping item placement error = %v, want invalid destination", err)
|
||||
}
|
||||
if _, _, err := placeDocumentWithMode(body, destination, placementMode(255), root, 3, 6); !errors.Is(err, errInvalidDestination) {
|
||||
if _, _, err := placeDocumentWithMode(body, destination, PlacementMode(255), root, 3, 6); !errors.Is(err, errInvalidDestination) {
|
||||
t.Fatalf("unknown placement mode error = %v, want invalid destination", err)
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ func TestPlaceDocumentSequenceItemAndMountedBounds(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := placeDocumentWithMode(body, destination, placementModeSequenceItem, root, test.depth, test.nodes)
|
||||
_, _, err := placeDocumentWithMode(body, destination, PlacementModeSequenceItem, root, test.depth, test.nodes)
|
||||
if test.wantAccept && err != nil {
|
||||
t.Fatalf("exact bounds rejected: %v", err)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ settings: {main: selected}
|
||||
importPath := writeImportFile(t, root, "fragments/extra.yml", "settings: {imported: value}\n")
|
||||
search := SearchConfig("app", SearchDirectory(root))
|
||||
options := Options[discoveryLoadConfig]{
|
||||
Imports: true, Filesystem: &FilesystemContext{Root: root}, destination: Keys("service"),
|
||||
Imports: true, Filesystem: &FilesystemContext{Root: root}, Destination: Keys("service"),
|
||||
}
|
||||
searched, err := testLoad(search, options)
|
||||
if err != nil {
|
||||
@@ -172,7 +172,7 @@ func TestSearchProbeFailureRetainsFileEvidence(t *testing.T) {
|
||||
load func(Source) (*Loaded[discoveryLoadConfig], error)
|
||||
}{
|
||||
{"ordinary", "source-1", func(source Source) (*Loaded[discoveryLoadConfig], error) {
|
||||
return Load(source, testSecretBinding(), Options[discoveryLoadConfig]{destination: Keys("settings")})
|
||||
return Load(source, testSecretBinding(), Options[discoveryLoadConfig]{Destination: Keys("settings")})
|
||||
}},
|
||||
{"underlay after acquired sources", "source-3", func(source Source) (*Loaded[discoveryLoadConfig], error) {
|
||||
return LoadLayered(Input{Source: File(main)}, testSecretBinding(), LayeredOptions[discoveryLoadConfig]{
|
||||
|
||||
@@ -94,7 +94,7 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
||||
}
|
||||
mainInfo := cloneSourceInfo(*main.source)
|
||||
mainInfo.Destination = destination.clone()
|
||||
mainIsItem := main.source.placementMode == placementModeSequenceItem
|
||||
mainIsItem := main.source.placementMode == PlacementModeSequenceItem
|
||||
if mainPath != "" {
|
||||
mainInfo.Path = mainPath
|
||||
}
|
||||
@@ -244,7 +244,7 @@ func (s *importTraversal) walkDeclarations(basePath string, declarations []impor
|
||||
if len(diagnostics) != 0 {
|
||||
return diagnostics
|
||||
}
|
||||
if policy.placement == placementModeSequenceItem && len(appendDestination(parentDestination, policy.destination).segments) == 0 {
|
||||
if policy.placement == PlacementModeSequenceItem && len(appendDestination(parentDestination, policy.destination).segments) == 0 {
|
||||
site := spec.fieldSites["placement"]
|
||||
return []Diagnostic{{Code: CodeImportInvalid, Severity: SeverityError, Path: site.path.clone(), Message: "sequence-item placement requires a nonempty destination", Primary: cloneLocation(&site.location)}}
|
||||
}
|
||||
@@ -305,8 +305,8 @@ func (s *importTraversal) admitImportSource(canonical string, identity resourceI
|
||||
label = s.access.label + "/" + canonical
|
||||
}
|
||||
info := SourceInfo{ID: sourceID, Label: label, Path: canonical, Destination: s.sourceDestination(destination), Layer: LayerBase, Kind: kind, ImportedFrom: &location}
|
||||
if policy.placement == placementModeSequenceItem {
|
||||
info.placementMode = placementModeSequenceItem
|
||||
if policy.placement == PlacementModeSequenceItem {
|
||||
info.placementMode = PlacementModeSequenceItem
|
||||
}
|
||||
// A source's own item placement still has an exact sequence-container
|
||||
// destination. Only an unresolved enclosing item index makes the path a
|
||||
@@ -433,17 +433,17 @@ func (s *importTraversal) visitPath(candidate selectedImportCandidate, spec impo
|
||||
admitted := admission.source
|
||||
|
||||
placementDestination := destination
|
||||
mode := placementModeMapping
|
||||
if policy.placement == placementModeSequenceItem {
|
||||
mode = placementModeSequenceItem
|
||||
mode := PlacementModeMapping
|
||||
if policy.placement == PlacementModeSequenceItem {
|
||||
mode = PlacementModeSequenceItem
|
||||
}
|
||||
role := importRoleMapping
|
||||
if mode == placementModeSequenceItem {
|
||||
if mode == PlacementModeSequenceItem {
|
||||
role = importRoleItem
|
||||
}
|
||||
s.importGraph.addNode(importGraphNode{key: admitted.nodeKey, canonical: admitted.canonical, sourceID: admitted.source.ID, role: role})
|
||||
s.importGraph.addEdge(importerKey, admitted.nodeKey, location)
|
||||
if mode == placementModeSequenceItem {
|
||||
if mode == PlacementModeSequenceItem {
|
||||
route := importRoute{canonical: admitted.canonical, locations: currentRoute.locations, key: admitted.nodeKey}
|
||||
s.active[admitted.identity] = len(s.stack)
|
||||
s.tier.visited[admitted.identity] = route
|
||||
|
||||
@@ -213,7 +213,7 @@ func projectAcquiredDestinations(composed *composedDocument, scope acquisitionSc
|
||||
itemIndex = projected
|
||||
}
|
||||
}
|
||||
if contribution.source.placementMode == placementModeSequenceItem {
|
||||
if contribution.source.placementMode == PlacementModeSequenceItem {
|
||||
container := appendDestination(contributionPrefix, contribution.destination)
|
||||
contribution.source.Destination = container.clone()
|
||||
contribution.source.destinationUnresolved = false
|
||||
|
||||
@@ -73,12 +73,12 @@ func composeAcquiredInputWithPolicies(input assembledInput, lower collectionPoli
|
||||
}
|
||||
completed.acquisition = []acquisitionScope{cloneAcquisitionScope(localScope)}
|
||||
projectNestedEvidence(completed, localScope)
|
||||
_, placed, err := placeDocumentWithMode(completed.root, main.destination, placementModeSequenceItem, main.payload.Location, maxDocumentDepth, maxDocumentNodes)
|
||||
_, placed, err := placeDocumentWithMode(completed.root, main.destination, PlacementModeSequenceItem, main.payload.Location, maxDocumentDepth, maxDocumentNodes)
|
||||
if err != nil {
|
||||
return nil, []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, main.source.ID, "configuration exceeds the source depth or node limit after destination placement")}
|
||||
}
|
||||
if !main.placementCharged {
|
||||
placementNodes := destinationWrapperNodeCountForMode(main.destination, placementModeSequenceItem)
|
||||
placementNodes := destinationWrapperNodeCountForMode(main.destination, PlacementModeSequenceItem)
|
||||
if accounting.nodes+placementNodes > traversal.policy.importLimits.nodes {
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", main.source.ImportedFrom)}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func reservePendingItemPlacements(scope *acquisitionScope, limits importLimits,
|
||||
if contribution.pendingItem == nil {
|
||||
continue
|
||||
}
|
||||
placementNodes := destinationWrapperNodeCountForMode(contribution.destination, placementModeSequenceItem)
|
||||
placementNodes := destinationWrapperNodeCountForMode(contribution.destination, PlacementModeSequenceItem)
|
||||
if accounting.nodes+placementNodes > limits.nodes {
|
||||
diagnostic := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", contribution.source.ImportedFrom)
|
||||
return &diagnostic
|
||||
@@ -228,11 +228,11 @@ func (s *importTraversal) composePendingItems(scope *acquisitionScope) []Diagnos
|
||||
// item has its effective coordinates, not against its local field names.
|
||||
completed.acquisition = []acquisitionScope{cloneAcquisitionScope(*itemScope)}
|
||||
projectNestedEvidence(completed, *itemScope)
|
||||
_, placed, err := placeDocumentWithMode(completed.root, contribution.destination, placementModeSequenceItem, contribution.payload.Location, maxDocumentDepth, maxDocumentNodes)
|
||||
_, placed, err := placeDocumentWithMode(completed.root, contribution.destination, PlacementModeSequenceItem, contribution.payload.Location, maxDocumentDepth, maxDocumentNodes)
|
||||
if err != nil {
|
||||
return []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the source depth or node limit after destination placement", contribution.source.ImportedFrom)}
|
||||
}
|
||||
placementNodes := destinationWrapperNodeCountForMode(contribution.destination, placementModeSequenceItem)
|
||||
placementNodes := destinationWrapperNodeCountForMode(contribution.destination, PlacementModeSequenceItem)
|
||||
if !contribution.placementCharged {
|
||||
if s.state.accounting.nodes+placementNodes > s.policy.importLimits.nodes {
|
||||
return []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", contribution.source.ImportedFrom)}
|
||||
|
||||
@@ -38,7 +38,7 @@ type importDeclarationSpec struct {
|
||||
depth int
|
||||
depthSet bool
|
||||
destination Path
|
||||
placement placementMode
|
||||
placement PlacementMode
|
||||
fieldSites map[string]importFieldSite
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ type resolvedImportPolicy struct {
|
||||
depthSet bool
|
||||
exclude []string
|
||||
destination Path
|
||||
placement placementMode
|
||||
placement PlacementMode
|
||||
}
|
||||
|
||||
func snapshotImportDefaults(value ImportDefaults) ImportDefaults {
|
||||
@@ -173,7 +173,7 @@ func parseImportDeclarationSpec(node *document.Node, declarationPath Path) (impo
|
||||
spec := importDeclarationSpec{
|
||||
path: declarationPath.clone(),
|
||||
location: publicLocation(node.Location),
|
||||
placement: placementModeMapping,
|
||||
placement: PlacementModeMapping,
|
||||
fieldSites: make(map[string]importFieldSite, len(node.Mapping)),
|
||||
}
|
||||
selectors := 0
|
||||
@@ -281,19 +281,19 @@ func parseImportWildcardAssignment(spec *importDeclarationSpec, field string, no
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseImportPlacement(node *document.Node, fieldPath Path) (placementMode, *Diagnostic) {
|
||||
func parseImportPlacement(node *document.Node, fieldPath Path) (PlacementMode, *Diagnostic) {
|
||||
if node.Kind != document.String {
|
||||
diagnostic := nodeImportDiagnostic(CodeImportInvalid, fieldPath, "placement must be mapping or sequence-item", node)
|
||||
return placementModeMapping, &diagnostic
|
||||
return PlacementModeMapping, &diagnostic
|
||||
}
|
||||
switch node.Text {
|
||||
case "mapping":
|
||||
return placementModeMapping, nil
|
||||
return PlacementModeMapping, nil
|
||||
case "sequence-item":
|
||||
return placementModeSequenceItem, nil
|
||||
return PlacementModeSequenceItem, nil
|
||||
default:
|
||||
diagnostic := nodeImportDiagnostic(CodeImportInvalid, fieldPath, "placement must be mapping or sequence-item", node)
|
||||
return placementModeMapping, &diagnostic
|
||||
return PlacementModeMapping, &diagnostic
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestParseImportDeclarationSpecNormalizesPresenceAndPlacement(t *testing.T)
|
||||
if first.selector != importSelectorPath || len(first.paths) != 2 || first.paths[0] != "one.yaml" || first.paths[1] != "two.yaml" {
|
||||
t.Fatalf("path selector = %#v", first)
|
||||
}
|
||||
if first.required == nil || *first.required || first.destination.String() != "/services" || first.placement != placementModeSequenceItem {
|
||||
if first.required == nil || *first.required || first.destination.String() != "/services" || first.placement != PlacementModeSequenceItem {
|
||||
t.Fatalf("explicit declaration values = %#v", first)
|
||||
}
|
||||
if first.path.String() != "/configkit/imports/0" || first.fieldSites["required"].path.String() != "/configkit/imports/0/required" {
|
||||
|
||||
@@ -413,7 +413,7 @@ label: helper
|
||||
loaded, err := LoadLayered(
|
||||
Input{Source: NoSource(), Imports: true}, testSecretBinding(),
|
||||
LayeredOptions[config]{Underlays: []Underlay{{Inputs: []Input{{
|
||||
Source: File(itemPath), Imports: true, Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem,
|
||||
Source: File(itemPath), Imports: true, Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem,
|
||||
}}}}},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -503,7 +503,7 @@ func TestLoadItemGlobKeepsDefaultModeIndependentAndOptionalMissesAbsent(t *testi
|
||||
t.Fatalf("config = %#v", result.Config)
|
||||
}
|
||||
sources := result.Sources()
|
||||
if len(sources) != 3 || sources[1].Path != canonicalTestPath(t, emptyPath) || sources[1].Destination.String() != "/items" || sources[1].placementMode != placementModeSequenceItem || sources[2].placementMode != placementModeMapping || sources[2].Destination.String() != "/other" {
|
||||
if len(sources) != 3 || sources[1].Path != canonicalTestPath(t, emptyPath) || sources[1].Destination.String() != "/items" || sources[1].placementMode != PlacementModeSequenceItem || sources[2].placementMode != PlacementModeMapping || sources[2].Destination.String() != "/other" {
|
||||
t.Fatalf("source placement evidence = %#v", sources)
|
||||
}
|
||||
}
|
||||
@@ -521,7 +521,7 @@ func TestLoadMainItemPlacementKeepsItsHelpersInTheItem(t *testing.T) {
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: helper.yml\nid: main\n")
|
||||
helperPath := writeImportFile(t, directory, "helper.yml", "value: helper\n")
|
||||
result, err := testLoad[config](File(mainPath), Options[config]{
|
||||
Imports: true, destination: Keys("items"), placementMode: placementModeSequenceItem,
|
||||
Imports: true, Destination: Keys("items"), PlacementMode: PlacementModeSequenceItem,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("load main item: %v", err)
|
||||
@@ -530,7 +530,7 @@ func TestLoadMainItemPlacementKeepsItsHelpersInTheItem(t *testing.T) {
|
||||
t.Fatalf("main item = %#v", result.Config.Items)
|
||||
}
|
||||
sources := result.Sources()
|
||||
if len(sources) != 2 || sources[0].Destination.String() != "/items" || sources[0].placementMode != placementModeSequenceItem || sources[1].Destination.String() != "/items/0" || sources[1].placementMode != placementModeMapping {
|
||||
if len(sources) != 2 || sources[0].Destination.String() != "/items" || sources[0].placementMode != PlacementModeSequenceItem || sources[1].Destination.String() != "/items/0" || sources[1].placementMode != PlacementModeMapping {
|
||||
t.Fatalf("main item sources = %#v", sources)
|
||||
}
|
||||
if sources[1].Path != canonicalTestPath(t, helperPath) {
|
||||
@@ -549,7 +549,7 @@ func TestProjectAcquiredDestinationsUsesMappedSequenceItemIndex(t *testing.T) {
|
||||
items: []sequenceItemProjection{{inputIndex: 0, outputIndex: 2}},
|
||||
}}}
|
||||
scope := acquisitionScope{contributions: []acquiredContribution{{
|
||||
source: SourceInfo{ID: "outer-source", placementMode: placementModeSequenceItem},
|
||||
source: SourceInfo{ID: "outer-source", placementMode: PlacementModeSequenceItem},
|
||||
destination: Keys("records"), nested: child,
|
||||
}}}
|
||||
sources := []SourceInfo{{ID: "outer-source"}, {ID: "nested-source"}}
|
||||
@@ -760,7 +760,7 @@ func TestParseImportPlacementDefaultsPerDeclaration(t *testing.T) {
|
||||
- glob: records/*.yml
|
||||
placement: sequence-item
|
||||
`)
|
||||
if len(declarations) != 2 || declarations[0].placement != placementModeMapping || declarations[1].placement != placementModeSequenceItem {
|
||||
if len(declarations) != 2 || declarations[0].placement != PlacementModeMapping || declarations[1].placement != PlacementModeSequenceItem {
|
||||
t.Fatalf("declaration placements = %#v", declarations)
|
||||
}
|
||||
}
|
||||
@@ -1107,7 +1107,7 @@ id: item
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: helper.yml}]}\nid: main\n")
|
||||
writeImportFile(t, directory, "helper.yml", "id: helper\n")
|
||||
options := Options[importTestConfig]{
|
||||
Imports: true, destination: Keys("items"), placementMode: placementModeSequenceItem,
|
||||
Imports: true, Destination: Keys("items"), PlacementMode: PlacementModeSequenceItem,
|
||||
}
|
||||
loadError := requireLoadCode(t, File(mainPath), options, CodeComposeConflict)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
|
||||
@@ -8,7 +8,7 @@ type Input struct {
|
||||
Imports bool
|
||||
Filesystem *FilesystemContext
|
||||
Destination Path
|
||||
placementMode placementMode
|
||||
PlacementMode PlacementMode
|
||||
}
|
||||
|
||||
// Underlay contains strictly composed contributions at one precedence tier.
|
||||
@@ -38,7 +38,7 @@ func LoadLayered[T any](main Input, secrets SecretBinding, supplied ...LayeredOp
|
||||
request := loadRequest[T]{
|
||||
main: loadInput{
|
||||
source: main.Source, imports: main.Imports, filesystem: main.Filesystem,
|
||||
destination: main.Destination.clone(), placementMode: main.placementMode,
|
||||
destination: main.Destination.clone(), placementMode: main.PlacementMode,
|
||||
},
|
||||
definition: options.Definition, sourceVersionMode: options.SourceVersionMode,
|
||||
importDefaults: options.ImportDefaults,
|
||||
@@ -52,7 +52,7 @@ func LoadLayered[T any](main Input, secrets SecretBinding, supplied ...LayeredOp
|
||||
for inputIndex, input := range underlay.Inputs {
|
||||
request.underlays[index].inputs[inputIndex] = loadInput{
|
||||
source: input.Source, imports: input.Imports, filesystem: input.Filesystem,
|
||||
destination: input.Destination.clone(), placementMode: input.placementMode,
|
||||
destination: input.Destination.clone(), placementMode: input.PlacementMode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ type Options[T any] struct {
|
||||
Overrides []Override
|
||||
SourceVersionMode sourceVersionMode
|
||||
ImportDefaults ImportDefaults
|
||||
destination Path
|
||||
placementMode placementMode
|
||||
Destination Path
|
||||
PlacementMode PlacementMode
|
||||
}
|
||||
|
||||
// FilesystemContext supplies filesystem roots for imports and overlays. For an
|
||||
@@ -161,7 +161,7 @@ func loadWithSecretLookupLimit[T any](source Source, secrets SecretBinding, look
|
||||
}
|
||||
input, diagnostics := normalizeInput(loadInput{
|
||||
source: source, imports: options.Imports, filesystem: options.Filesystem,
|
||||
destination: options.destination.clone(), placementMode: options.placementMode,
|
||||
destination: options.Destination.clone(), placementMode: options.PlacementMode,
|
||||
}, options.Overlay)
|
||||
defaults, policy, settingsDiagnostics := loadSettings(options.ImportDefaults, options.Definition, options.SourceVersionMode)
|
||||
diagnostics = append(diagnostics, settingsDiagnostics...)
|
||||
|
||||
@@ -32,7 +32,7 @@ type loadInput struct {
|
||||
imports bool
|
||||
filesystem *FilesystemContext
|
||||
destination Path
|
||||
placementMode placementMode
|
||||
placementMode PlacementMode
|
||||
}
|
||||
|
||||
type loadGroup struct{ inputs []loadInput }
|
||||
|
||||
@@ -161,8 +161,8 @@ func TestUnderlayItemConflictUsesScheduledGroupIndex(t *testing.T) {
|
||||
request := loadRequest[map[string]any]{
|
||||
main: loadInput{source: NoSource()},
|
||||
underlays: []loadGroup{{inputs: []loadInput{
|
||||
{source: File(zItem), destination: Keys("items"), placementMode: placementModeSequenceItem},
|
||||
{source: File(aItem), destination: Keys("items"), placementMode: placementModeSequenceItem},
|
||||
{source: File(zItem), destination: Keys("items"), placementMode: PlacementModeSequenceItem},
|
||||
{source: File(aItem), destination: Keys("items"), placementMode: PlacementModeSequenceItem},
|
||||
}}},
|
||||
definition: Definition[map[string]any]{sequenceIdentityRegistrations: []sequenceIdentityRegistration{{selector: sequenceIdentitySelector{literalSequenceSelector("items")}, identityFields: []string{"id"}}}},
|
||||
}
|
||||
@@ -205,8 +205,8 @@ func TestUnderlayItemHelperConflictUsesScheduledGroupIndex(t *testing.T) {
|
||||
request := loadRequest[map[string]any]{
|
||||
main: loadInput{source: NoSource()},
|
||||
underlays: []loadGroup{{inputs: []loadInput{
|
||||
{source: File(zBad), imports: true, destination: Keys("items"), placementMode: placementModeSequenceItem},
|
||||
{source: File(aGood), destination: Keys("items"), placementMode: placementModeSequenceItem},
|
||||
{source: File(zBad), imports: true, destination: Keys("items"), placementMode: PlacementModeSequenceItem},
|
||||
{source: File(aGood), destination: Keys("items"), placementMode: PlacementModeSequenceItem},
|
||||
}}},
|
||||
definition: Definition[map[string]any]{sequenceIdentityRegistrations: []sequenceIdentityRegistration{{selector: sequenceIdentitySelector{literalSequenceSelector("items")}, identityFields: []string{"id"}}}},
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package engine
|
||||
|
||||
func normalizeInput(input loadInput, ordinaryOverlay string) (loadInput, []Diagnostic) {
|
||||
var diagnostics []Diagnostic
|
||||
if input.placementMode != placementModeMapping && input.placementMode != placementModeSequenceItem {
|
||||
if input.placementMode != PlacementModeMapping && input.placementMode != PlacementModeSequenceItem {
|
||||
diagnostics = append(diagnostics, optionDiagnostic(CodeOptionsInvalid, "input placement mode is invalid"))
|
||||
}
|
||||
if normalized, err := normalizeDestination(input.destination); err != nil {
|
||||
@@ -10,7 +10,7 @@ func normalizeInput(input loadInput, ordinaryOverlay string) (loadInput, []Diagn
|
||||
} else {
|
||||
input.destination = normalized
|
||||
}
|
||||
if input.placementMode == placementModeSequenceItem && len(input.destination.segments) == 0 {
|
||||
if input.placementMode == PlacementModeSequenceItem && len(input.destination.segments) == 0 {
|
||||
diagnostics = append(diagnostics, optionDiagnostic(CodeOptionsInvalid, "sequence-item placement requires a nonempty destination"))
|
||||
}
|
||||
if input.filesystem != nil {
|
||||
|
||||
@@ -196,7 +196,7 @@ type SourceInfo struct {
|
||||
VersionCheck *SourceVersionCheck
|
||||
importSelections []importSelectionEvidence
|
||||
namespace *namespaceToken
|
||||
placementMode placementMode
|
||||
placementMode PlacementMode
|
||||
destinationUnresolved bool
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ func TestLoadingClosesNativeFilesAcrossPipelineOutcomes(t *testing.T) {
|
||||
child: "configkit: {imports: [{path: helper.yml}]}\nid: child\nvalue: child\n",
|
||||
helper: "value: helper\n",
|
||||
options: Options[config]{
|
||||
Imports: true, destination: Keys("groups"), placementMode: placementModeSequenceItem,
|
||||
Imports: true, Destination: Keys("groups"), PlacementMode: PlacementModeSequenceItem,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
||||
@@ -132,7 +132,7 @@ func loadSelectedOverlay(request selectedOverlayRequest, access *filesystemAcces
|
||||
var failures []Diagnostic
|
||||
if versionState != nil {
|
||||
processed, failures = versionState.processWithDirectiveContext(
|
||||
overlayRoot, sourceVersionContribution, Path{}, sourceID, placementModeMapping, rootDirectiveContextOverlay,
|
||||
overlayRoot, sourceVersionContribution, Path{}, sourceID, PlacementModeMapping, rootDirectiveContextOverlay,
|
||||
)
|
||||
} else {
|
||||
processed = processSourceVersionWithDirectiveContext(
|
||||
|
||||
@@ -117,19 +117,19 @@ func (evidence *sourceVersionEvidence) sensitivityPaths() []Path {
|
||||
return paths
|
||||
}
|
||||
|
||||
func (state *sourceVersionState) process(root *document.Node, role sourceVersionRole, destination Path, sourceID string, placement placementMode) (sourceVersionProcessingResult, []Diagnostic) {
|
||||
func (state *sourceVersionState) process(root *document.Node, role sourceVersionRole, destination Path, sourceID string, placement PlacementMode) (sourceVersionProcessingResult, []Diagnostic) {
|
||||
if state == nil || state.mode == sourceVersionModeDefault {
|
||||
return sourceVersionProcessingResult{}, nil
|
||||
}
|
||||
return state.processWithDirectiveContext(root, role, destination, sourceID, placement, rootDirectiveContextImportsOnly)
|
||||
}
|
||||
|
||||
func (state *sourceVersionState) processWithDirectiveContext(root *document.Node, role sourceVersionRole, destination Path, sourceID string, placement placementMode, directiveContext rootDirectiveContext) (sourceVersionProcessingResult, []Diagnostic) {
|
||||
func (state *sourceVersionState) processWithDirectiveContext(root *document.Node, role sourceVersionRole, destination Path, sourceID string, placement PlacementMode, directiveContext rootDirectiveContext) (sourceVersionProcessingResult, []Diagnostic) {
|
||||
if state == nil {
|
||||
return sourceVersionProcessingResult{}, nil
|
||||
}
|
||||
projectedDestination := destination.clone()
|
||||
if placement == placementModeSequenceItem {
|
||||
if placement == PlacementModeSequenceItem {
|
||||
projectedDestination = projectedDestination.Index(0)
|
||||
}
|
||||
result := processSourceVersionWithDirectiveContext(root, state.localRule, role, projectedDestination, state.mode, directiveContext)
|
||||
@@ -158,10 +158,10 @@ type sourceVersionProcessingResult struct {
|
||||
}
|
||||
|
||||
func effectiveSourceVersionRule(local *VersionRule, destination Path, mode sourceVersionMode) *VersionRule {
|
||||
return effectiveSourceVersionRuleForPlacement(local, destination, mode, placementModeMapping)
|
||||
return effectiveSourceVersionRuleForPlacement(local, destination, mode, PlacementModeMapping)
|
||||
}
|
||||
|
||||
func effectiveSourceVersionRuleForPlacement(local *VersionRule, destination Path, mode sourceVersionMode, placement placementMode) *VersionRule {
|
||||
func effectiveSourceVersionRuleForPlacement(local *VersionRule, destination Path, mode sourceVersionMode, placement PlacementMode) *VersionRule {
|
||||
if local == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -170,7 +170,7 @@ func effectiveSourceVersionRuleForPlacement(local *VersionRule, destination Path
|
||||
}
|
||||
effective := *local
|
||||
prefix := destination.clone()
|
||||
if placement == placementModeSequenceItem {
|
||||
if placement == PlacementModeSequenceItem {
|
||||
prefix = prefix.Index(0)
|
||||
}
|
||||
effective.Path = Path{
|
||||
|
||||
@@ -142,11 +142,11 @@ func TestFragmentVersionClaimUsesAssignedSequenceProjection(t *testing.T) {
|
||||
t.Fatalf("destructive sequence ancestor claim = %#v, want mapping node", node)
|
||||
}
|
||||
|
||||
effective := effectiveSourceVersionRuleForPlacement(&VersionRule{Path: Keys("version")}, Keys("catalog", "entries"), sourceVersionModeRequired, placementModeSequenceItem)
|
||||
effective := effectiveSourceVersionRuleForPlacement(&VersionRule{Path: Keys("version")}, Keys("catalog", "entries"), sourceVersionModeRequired, PlacementModeSequenceItem)
|
||||
if got, want := effective.Path.String(), "/catalog/entries/0/version"; got != want {
|
||||
t.Fatalf("item effective version path = %q, want %q", got, want)
|
||||
}
|
||||
defaultRule := effectiveSourceVersionRuleForPlacement(&VersionRule{Path: Keys("version")}, Keys("catalog", "entries"), sourceVersionModeDefault, placementModeSequenceItem)
|
||||
defaultRule := effectiveSourceVersionRuleForPlacement(&VersionRule{Path: Keys("version")}, Keys("catalog", "entries"), sourceVersionModeDefault, PlacementModeSequenceItem)
|
||||
if got, want := defaultRule.Path.String(), "/version"; got != want {
|
||||
t.Fatalf("default effective version path = %q, want %q", got, want)
|
||||
}
|
||||
@@ -628,7 +628,7 @@ func TestSourceVersionItemPlacementKeepsLocalChecksAndProtectsProjectedPath(t *t
|
||||
load: func(definition Definition[map[string]any]) error {
|
||||
_, err := Load(Mapping("main", map[string]any{"version": "v1", "name": "ordinary"}), testSecretBinding(), Options[map[string]any]{
|
||||
Definition: definition, SourceVersionMode: sourceVersionModeRequired,
|
||||
destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem,
|
||||
Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem,
|
||||
Overrides: []Override{{Path: Keys("catalog", "entries"), Value: []any{}, Flag: "--entries"}},
|
||||
})
|
||||
return err
|
||||
@@ -637,7 +637,7 @@ func TestSourceVersionItemPlacementKeepsLocalChecksAndProtectsProjectedPath(t *t
|
||||
{
|
||||
name: "layered",
|
||||
load: func(definition Definition[map[string]any]) error {
|
||||
_, err := LoadLayered(Input{Source: Mapping("main", map[string]any{"version": "v1", "name": "layered"}), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem}, testSecretBinding(), LayeredOptions[map[string]any]{
|
||||
_, err := LoadLayered(Input{Source: Mapping("main", map[string]any{"version": "v1", "name": "layered"}), Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem}, testSecretBinding(), LayeredOptions[map[string]any]{
|
||||
Definition: definition, SourceVersionMode: sourceVersionModeRequired,
|
||||
Overrides: []Override{{Path: Keys("catalog", "entries"), Value: []any{}, Flag: "--entries"}},
|
||||
})
|
||||
@@ -682,7 +682,7 @@ func TestSourceVersionItemEvidenceUsesProjectedSensitivityPath(t *testing.T) {
|
||||
Secret: func(path Path) bool { return path.String() == secretPath.String() },
|
||||
},
|
||||
SourceVersionMode: sourceVersionModeRequired,
|
||||
destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem,
|
||||
Destination: Keys("catalog", "entries"), PlacementMode: PlacementModeSequenceItem,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("item source-version load: %v", err)
|
||||
|
||||
@@ -65,8 +65,9 @@ func toEngineInput(input Input) engine.Input {
|
||||
result := engine.Input{
|
||||
Source: input.Source.toEngine(), Imports: input.Imports,
|
||||
Filesystem: toEngineFilesystemContext(input.Filesystem), Destination: toEnginePath(input.Destination),
|
||||
PlacementMode: engine.PlacementMode(input.PlacementMode),
|
||||
}
|
||||
return engine.InputWithPlacement(result, uint8(input.PlacementMode))
|
||||
return result
|
||||
}
|
||||
|
||||
func toEngineLayeredOptions[T any](options LayeredOptions[T]) engine.LayeredOptions[T] {
|
||||
|
||||
@@ -318,8 +318,9 @@ func toEngineOptions[T any](options Options[T]) engine.Options[T] {
|
||||
Overlay: options.Overlay,
|
||||
SourceVersionMode: engine.SourceVersionModeFromFacade(uint8(options.SourceVersionMode)),
|
||||
ImportDefaults: toEngineImportDefaults(options.ImportDefaults),
|
||||
Destination: toEnginePath(options.Destination.clone()),
|
||||
PlacementMode: engine.PlacementMode(options.PlacementMode),
|
||||
}
|
||||
result = engine.OptionsWithPlacement(result, toEnginePath(options.Destination.clone()), uint8(options.PlacementMode))
|
||||
if options.Filesystem != nil {
|
||||
result.Filesystem = toEngineFilesystemContext(options.Filesystem)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ func TestOverlayPublicValues(t *testing.T) {
|
||||
func TestSourceInfoDestinationConversion(t *testing.T) {
|
||||
destination := Keys("collections", "a/b", "0")
|
||||
path := writeRecordConfig(t, "value: main\n")
|
||||
options := engine.OptionsWithPlacement(engine.Options[map[string]any]{}, engine.Keys("collections", "a/b", "0"), uint8(PlacementModeSequenceItem))
|
||||
options := engine.Options[map[string]any]{
|
||||
Destination: engine.Keys("collections", "a/b", "0"), PlacementMode: engine.PlacementMode(PlacementModeSequenceItem),
|
||||
}
|
||||
internal := engineSourceInfoFromLoad(t, path, "source-1", options)
|
||||
converted := fromEngineSourceInfo(internal)
|
||||
if converted.Destination.String() != destination.String() || converted.PlacementMode != PlacementModeSequenceItem || converted.DestinationUnresolved {
|
||||
|
||||
Reference in New Issue
Block a user