Consolidate engine import defaults

This commit is contained in:
2026-10-26 00:10:07 +00:00
parent 7d18c93339
commit c25cf39d19
13 changed files with 58 additions and 86 deletions

View File

@@ -3,7 +3,7 @@ package engine
import "strconv"
type acquisitionPolicy struct {
importDefaults importDefaults
importDefaults ImportDefaults
sequencePolicy sequencePolicy
importLimits importLimits
}

View File

@@ -255,7 +255,7 @@ func selectDirectoryWithDiagnostics(t *testing.T, access *filesystemAccess, base
if len(diagnostics) != 0 {
t.Fatalf("parse diagnostics = %#v", diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatalf("policy diagnostics = %#v", diagnostics)
}

View File

@@ -34,7 +34,7 @@ func TestSelectShallowDirectoriesUnionsRootsAndPatterns(t *testing.T) {
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -82,7 +82,7 @@ func TestSelectShallowDirectoriesIncludeUnrestrictedHiddenAndExtensionlessFiles(
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -141,7 +141,7 @@ func TestSelectShallowDirectoriesApplyRequirednessToFinalUnion(t *testing.T) {
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -173,7 +173,7 @@ func TestSelectShallowDirectoryRejectsInvalidRootInsteadOfTreatingItAsMissing(t
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -188,7 +188,7 @@ func TestSelectShallowDirectoryRejectsInvalidRootInsteadOfTreatingItAsMissing(t
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics = resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics = resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -218,7 +218,7 @@ func TestSelectShallowDirectoryFiltersSymlinkAliasSpelling(t *testing.T) {
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -254,7 +254,7 @@ func TestSelectDirectoriesApplyRecursiveDepthToFileLevels(t *testing.T) {
for _, test := range []struct {
name string
yaml string
defaults importDefaults
defaults ImportDefaults
wantPaths []string
}{
{
@@ -280,13 +280,13 @@ func TestSelectDirectoriesApplyRecursiveDepthToFileLevels(t *testing.T) {
{
name: "explicit false overrides application recursion",
yaml: " - dir: .\n recursive: false\n pattern: '*.yaml'\n",
defaults: importDefaults{recursive: boolPointer(true)},
defaults: ImportDefaults{Recursive: boolPointer(true)},
wantPaths: []string{"direct.yaml"},
},
{
name: "application default enables recursion for depth",
yaml: " - dir: .\n depth: 2\n pattern: '*.yaml'\n",
defaults: importDefaults{recursive: boolPointer(true)},
defaults: ImportDefaults{Recursive: boolPointer(true)},
wantPaths: []string{"child.yaml", "direct.yaml"},
},
{
@@ -347,7 +347,7 @@ func TestSelectDirectoriesRetainsEmptySearchAndDirectoryVisitLimits(t *testing.T
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}

View File

@@ -99,7 +99,7 @@ func TestSelectGlobAppliesExclusionsBeforeSourceAdmissionWithoutOpeningFiles(t *
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -181,7 +181,7 @@ func selectGlobForTestWithDiagnostics(t *testing.T, access *filesystemAccess, ba
if len(diagnostics) != 0 {
t.Fatalf("parse diagnostics = %#v", diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatalf("policy diagnostics = %#v", diagnostics)
}

View File

@@ -67,7 +67,7 @@ func TestSelectNamedImportsChecksRequiredTargetsBeforeExclusions(t *testing.T) {
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -118,7 +118,7 @@ func TestSelectNamedImportsDoesNotOpenExcludedContentOrApplySearchControls(t *te
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
@@ -135,7 +135,7 @@ func TestSelectNamedImportsDoesNotOpenExcludedContentOrApplySearchControls(t *te
t.Fatal(diagnostics)
}
hidden := false
privatePolicy, policyDiagnostics := resolveImportPolicy(private[0], importDefaults{hidden: &hidden})
privatePolicy, policyDiagnostics := resolveImportPolicy(private[0], ImportDefaults{Hidden: &hidden})
if len(policyDiagnostics) != 0 || !privatePolicy.hidden {
t.Fatalf("path selector accepted search-only defaults: %#v, %#v", privatePolicy, policyDiagnostics)
}

View File

@@ -42,15 +42,6 @@ type importDeclarationSpec struct {
fieldSites map[string]importFieldSite
}
// importDefaults are the engine's private copy of load-wide discovery defaults.
type importDefaults struct {
required *bool
follow *bool
hidden *bool
recursive *bool
pattern []string
}
// ImportDefaults transports root-owned load defaults across the facade
// boundary. Load options snapshot this value before source acquisition.
type ImportDefaults struct {
@@ -65,26 +56,6 @@ type ImportDefaults struct {
// Pattern filters directory-search filenames; nil and empty differ.
Pattern []string
}
// OptionsWithImportDefaults copies root-owned defaults into ordinary options.
func OptionsWithImportDefaults[T any](options Options[T], value ImportDefaults) Options[T] {
options.importDefaults = privateImportDefaults(value)
return options
}
// LayeredOptionsWithImportDefaults copies root-owned defaults into grouped options.
func LayeredOptionsWithImportDefaults[T any](options LayeredOptions[T], value ImportDefaults) LayeredOptions[T] {
options.importDefaults = privateImportDefaults(value)
return options
}
func privateImportDefaults(value ImportDefaults) importDefaults {
return snapshotImportDefaults(importDefaults{
required: value.Required, follow: value.Follow, hidden: value.Hidden,
recursive: value.Recursive, pattern: value.Pattern,
})
}
type resolvedImportPolicy struct {
required bool
follow bool
@@ -98,13 +69,13 @@ type resolvedImportPolicy struct {
placement placementMode
}
func snapshotImportDefaults(value importDefaults) importDefaults {
return importDefaults{
required: cloneBool(value.required),
follow: cloneBool(value.follow),
hidden: cloneBool(value.hidden),
recursive: cloneBool(value.recursive),
pattern: cloneStrings(value.pattern),
func snapshotImportDefaults(value ImportDefaults) ImportDefaults {
return ImportDefaults{
Required: cloneBool(value.Required),
Follow: cloneBool(value.Follow),
Hidden: cloneBool(value.Hidden),
Recursive: cloneBool(value.Recursive),
Pattern: cloneStrings(value.Pattern),
}
}
@@ -123,8 +94,8 @@ func cloneStrings(values []string) []string {
return append(make([]string, 0, len(values)), values...)
}
func validateImportDefaults(value importDefaults) []Diagnostic {
for _, pattern := range value.pattern {
func validateImportDefaults(value ImportDefaults) []Diagnostic {
for _, pattern := range value.Pattern {
if _, err := path.Match(pattern, ""); err != nil {
return []Diagnostic{optionDiagnostic(CodeOptionsInvalid, "import default pattern is invalid")}
}
@@ -132,10 +103,10 @@ func validateImportDefaults(value importDefaults) []Diagnostic {
return nil
}
func resolveImportPolicy(spec importDeclarationSpec, defaults importDefaults) (resolvedImportPolicy, []Diagnostic) {
func resolveImportPolicy(spec importDeclarationSpec, defaults ImportDefaults) (resolvedImportPolicy, []Diagnostic) {
defaults = snapshotImportDefaults(defaults)
policy := resolvedImportPolicy{
required: boolOr(spec.required, defaults.required, false),
required: boolOr(spec.required, defaults.Required, false),
follow: true,
hidden: true,
recursive: false,
@@ -146,15 +117,15 @@ func resolveImportPolicy(spec importDeclarationSpec, defaults importDefaults) (r
exclude: cloneStrings(spec.exclude),
}
if spec.selector == importSelectorDirectory || spec.selector == importSelectorGlob {
policy.follow = boolOr(spec.follow, defaults.follow, true)
policy.hidden = boolOr(spec.hidden, defaults.hidden, true)
policy.follow = boolOr(spec.follow, defaults.Follow, true)
policy.hidden = boolOr(spec.hidden, defaults.Hidden, true)
}
if spec.selector == importSelectorDirectory {
policy.recursive = boolOr(spec.recursive, defaults.recursive, false)
policy.recursive = boolOr(spec.recursive, defaults.Recursive, false)
if spec.patternSet {
policy.pattern = cloneStrings(spec.pattern)
} else {
policy.pattern = cloneStrings(defaults.pattern)
policy.pattern = cloneStrings(defaults.Pattern)
}
}
if spec.depthSet && !policy.recursive {

View File

@@ -123,13 +123,13 @@ func TestParseImportDeclarationSpecValidatesDepthSyntaxAndPolicy(t *testing.T) {
if len(diagnostics) != 0 {
t.Fatalf("syntax-only parse diagnostics = %#v", diagnostics)
}
_, diagnostics = resolveImportPolicy(specs[0], importDefaults{})
_, diagnostics = resolveImportPolicy(specs[0], ImportDefaults{})
if len(diagnostics) != 1 || diagnostics[0].Path.String() != "/configkit/imports/0/depth" {
t.Fatalf("policy diagnostics = %#v, want depth applicability error", diagnostics)
}
recursive := true
policy, diagnostics := resolveImportPolicy(specs[0], importDefaults{recursive: &recursive})
policy, diagnostics := resolveImportPolicy(specs[0], ImportDefaults{Recursive: &recursive})
if len(diagnostics) != 0 || !policy.recursive || policy.depth != 1 || !policy.depthSet {
t.Fatalf("application-default policy, diagnostics = %#v, %#v", policy, diagnostics)
}
@@ -142,7 +142,7 @@ func TestResolveImportPolicyAppliesDefaultsIndependently(t *testing.T) {
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
omitted, diagnostics := resolveImportPolicy(omittedSpecs[0], importDefaults{})
omitted, diagnostics := resolveImportPolicy(omittedSpecs[0], ImportDefaults{})
if len(diagnostics) != 0 || omitted.required || omitted.recursive || !omitted.follow || !omitted.hidden || omitted.pattern != nil {
t.Fatalf("library defaults = %#v, diagnostics = %#v", omitted, diagnostics)
}
@@ -159,12 +159,12 @@ func TestResolveImportPolicyAppliesDefaultsIndependently(t *testing.T) {
t.Fatal(diagnostics)
}
appRequired, appRecursive, appFollow, appHidden := true, true, true, true
defaults := importDefaults{
required: &appRequired,
recursive: &appRecursive,
follow: &appFollow,
hidden: &appHidden,
pattern: []string{"*.yaml"},
defaults := ImportDefaults{
Required: &appRequired,
Recursive: &appRecursive,
Follow: &appFollow,
Hidden: &appHidden,
Pattern: []string{"*.yaml"},
}
policy, diagnostics := resolveImportPolicy(specs[0], defaults)
if len(diagnostics) != 0 {
@@ -188,16 +188,16 @@ func TestResolveImportPolicyAppliesDefaultsIndependently(t *testing.T) {
}
snapshot := snapshotImportDefaults(defaults)
*defaults.required = false
defaults.pattern[0] = "*.toml"
if snapshot.required == nil || !*snapshot.required || snapshot.pattern[0] != "*.yaml" {
*defaults.Required = false
defaults.Pattern[0] = "*.toml"
if snapshot.Required == nil || !*snapshot.Required || snapshot.Pattern[0] != "*.yaml" {
t.Fatalf("snapshot shares mutable inputs: %#v", snapshot)
}
empty := snapshotImportDefaults(importDefaults{pattern: []string{}})
if empty.pattern == nil || len(empty.pattern) != 0 {
empty := snapshotImportDefaults(ImportDefaults{Pattern: []string{}})
if empty.Pattern == nil || len(empty.Pattern) != 0 {
t.Fatalf("snapshot lost explicit empty pattern: %#v", empty)
}
if snapshotImportDefaults(importDefaults{}).pattern != nil {
if snapshotImportDefaults(ImportDefaults{}).Pattern != nil {
t.Fatal("snapshot changed omitted pattern into explicit empty")
}
}
@@ -207,7 +207,7 @@ func TestInvalidImportDefaultPatternsFailBeforeReadingSource(t *testing.T) {
reader := &countingImportSpecReader{Reader: strings.NewReader("not: read\n")}
_, err := Load(Reader("invalid-default-pattern.yml", reader), testSecretBinding(), Options[struct{}]{
importDefaults: importDefaults{pattern: []string{"["}},
ImportDefaults: ImportDefaults{Pattern: []string{"["}},
})
var loadErr *LoadError
if !errors.As(err, &loadErr) || len(loadErr.Diagnostics()) == 0 || loadErr.Diagnostics()[0].Code != CodeOptionsInvalid {

View File

@@ -884,7 +884,7 @@ func TestImportDefaultsReachOrdinaryAndGroupedDeclarations(t *testing.T) {
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: child.yml}]}\n")
writeImportFile(t, directory, "child.yml", "configkit: {imports: [{path: absent.yml}]}\n")
_, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{
Imports: true, importDefaults: importDefaults{required: &required},
Imports: true, ImportDefaults: ImportDefaults{Required: &required},
})
var loadError *LoadError
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeImportMissing {
@@ -896,7 +896,7 @@ func TestImportDefaultsReachOrdinaryAndGroupedDeclarations(t *testing.T) {
_, err = loadGroupedWithSecretLookup(loadRequest[importTestConfig]{
main: loadInput{source: File(basePath)},
underlays: []loadGroup{{inputs: []loadInput{{source: File(underlayPath), imports: true}}}},
importDefaults: importDefaults{required: &required},
importDefaults: ImportDefaults{Required: &required},
}, testSecretBinding(), func(string) (string, bool) { return "", false })
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeImportMissing {
t.Fatalf("grouped underlay required default error = %#v", err)

View File

@@ -17,7 +17,7 @@ type Underlay struct{ Inputs []Input }
// LayeredOptions selects lower-priority tiers and final application rules.
type LayeredOptions[T any] struct {
Definition Definition[T]
importDefaults importDefaults
ImportDefaults ImportDefaults
SourceVersionMode sourceVersionMode
Underlays []Underlay
Overlay string
@@ -41,7 +41,7 @@ func LoadLayered[T any](main Input, secrets SecretBinding, supplied ...LayeredOp
destination: main.Destination.clone(), placementMode: main.placementMode,
},
definition: options.Definition, sourceVersionMode: options.SourceVersionMode,
importDefaults: snapshotImportDefaults(options.importDefaults),
importDefaults: snapshotImportDefaults(options.ImportDefaults),
overlay: options.Overlay,
overlayFilesystem: options.OverlayFilesystem,
overrides: append([]Override(nil), options.Overrides...),

View File

@@ -32,7 +32,7 @@ type Options[T any] struct {
Filesystem *FilesystemContext
Overrides []Override
SourceVersionMode sourceVersionMode
importDefaults importDefaults
ImportDefaults ImportDefaults
destination Path
placementMode placementMode
}
@@ -163,7 +163,7 @@ func loadWithSecretLookupLimit[T any](source Source, secrets SecretBinding, look
source: source, imports: options.Imports, filesystem: options.Filesystem,
destination: options.destination.clone(), placementMode: options.placementMode,
}, options.Overlay)
defaults, policy, settingsDiagnostics := loadSettings(options.importDefaults, options.Definition, options.SourceVersionMode)
defaults, policy, settingsDiagnostics := loadSettings(options.ImportDefaults, options.Definition, options.SourceVersionMode)
diagnostics = append(diagnostics, settingsDiagnostics...)
diagnostics = append(diagnostics, overlayOptionDiagnostics(options.Overlay)...)
if len(diagnostics) != 0 {

View File

@@ -10,7 +10,7 @@ type loadRequest[T any] struct {
main loadInput
underlays []loadGroup
definition Definition[T]
importDefaults importDefaults
importDefaults ImportDefaults
sequencePolicy sequencePolicy
sourceVersionMode sourceVersionMode
effectiveVersion *VersionRule

View File

@@ -35,7 +35,7 @@ func normalizeInput(input loadInput, ordinaryOverlay string) (loadInput, []Diagn
return input, canonicalDiagnostics(diagnostics)
}
func loadSettings[T any](defaults importDefaults, definition Definition[T], mode sourceVersionMode) (importDefaults, sequencePolicy, []Diagnostic) {
func loadSettings[T any](defaults ImportDefaults, definition Definition[T], mode sourceVersionMode) (ImportDefaults, sequencePolicy, []Diagnostic) {
defaults = snapshotImportDefaults(defaults)
var diagnostics []Diagnostic
diagnostics = append(diagnostics, validateImportDefaults(defaults)...)