Unify host and native filesystem acquisition

This commit is contained in:
2026-09-29 17:29:01 +00:00
parent de28718941
commit 6111cb23a1
8 changed files with 636 additions and 122 deletions

View File

@@ -4,10 +4,7 @@ import (
"bytes"
"errors"
"io/fs"
"os"
"path/filepath"
"strconv"
"strings"
yamladapter "gitea.maximumdirect.net/eric/ConfigKit/internal/yaml"
)
@@ -41,12 +38,32 @@ func loadSelectedOverlayDocument(source Source, context *FilesystemContext, main
}
func loadSelectedOverlayInto(source Source, context *FilesystemContext, main parsedSource, base *assemblyAccumulator, sources []SourceInfo, name string, rule *VersionRule, limits importLimits) ([]SourceInfo, []Diagnostic) {
if source.kind == sourceFilesystem {
access := newNativeAccess(source.namespace.filesystem, ".", source.namespace.token)
return loadSelectedOverlayWithAccess(access, base, sources, name, rule, limits)
}
rootPath, _, _, diagnostic := importFilesystem(source, context, main)
if diagnostic != nil {
return cloneSourceInfos(sources), []Diagnostic{*diagnostic}
}
overlayPath := filepath.Join(rootPath, "overlays", name+".yml")
canonical, err := canonicalExistingPath(overlayPath)
access, err := openHostAccess(rootPath)
if err != nil {
value := globFilesystemDiagnostic(err, "configuration root could not be opened for the selected overlay", Location{})
value.Primary = nil
return cloneSourceInfos(sources), []Diagnostic{value}
}
return loadSelectedOverlayWithAccess(access, base, sources, name, rule, limits)
}
func loadSelectedOverlayWithAccess(access *filesystemAccess, base *assemblyAccumulator, sources []SourceInfo, name string, rule *VersionRule, limits importLimits) ([]SourceInfo, []Diagnostic) {
closed := false
defer func() {
if !closed {
_ = access.close()
}
}()
overlayPath := access.join(access.rootPath, "overlays/"+name+".yml")
canonical, err := access.canonical(overlayPath)
if err != nil {
code := CodeOverlayInvalid
message := "selected overlay could not be resolved"
@@ -57,7 +74,7 @@ func loadSelectedOverlayInto(source Source, context *FilesystemContext, main par
}
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(code, message, nil)}
}
if !containedPath(rootPath, canonical) {
if !access.contains(canonical) {
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayOutsideRoot, "selected overlay resolves outside the configuration root", nil)}
}
for _, existing := range sources {
@@ -69,28 +86,15 @@ func loadSelectedOverlayInto(source Source, context *FilesystemContext, main par
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayLimitExceeded, "selected overlay exceeds the source-count limit", nil)}
}
root, err := os.OpenRoot(rootPath)
if err != nil {
value := globFilesystemDiagnostic(err, "configuration root could not be opened for the selected overlay", Location{})
value.Primary = nil
return cloneSourceInfos(sources), []Diagnostic{value}
}
rootClosed := false
defer func() {
if !rootClosed {
_ = root.Close()
}
}()
relative, err := filepath.Rel(rootPath, canonical)
if err != nil || filepath.IsAbs(relative) || relative == ".." || strings.HasPrefix(relative, ".."+string(filepath.Separator)) {
if _, err := access.relative(canonical); err != nil {
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayOutsideRoot, "selected overlay could not be addressed inside the configuration root", nil)}
}
sourceID := "source-" + strconv.Itoa(len(sources)+1)
overlayLocation := &Location{SourceID: sourceID}
overlaySource := SourceInfo{ID: sourceID, Label: filepath.ToSlash(filepath.Join("overlays", name+".yml")), Path: canonical, Layer: LayerOverlay}
overlaySource := SourceInfo{ID: sourceID, Label: "overlays/" + name + ".yml", Path: canonical, Layer: LayerOverlay}
sources = append(cloneSourceInfos(sources), overlaySource)
data, diagnostic := readOverlayFile(root, relative, sourceID, limits.bytes-base.current.inputBytes)
data, diagnostic := readOverlayFile(access, canonical, sourceID, limits.bytes-base.current.inputBytes)
if diagnostic != nil {
return sources, []Diagnostic{*diagnostic}
}
@@ -112,8 +116,8 @@ func loadSelectedOverlayInto(source Source, context *FilesystemContext, main par
Message: "overlays cannot contribute to or replace the schema-version path", Primary: &location,
}}
}
closeErr := root.Close()
rootClosed = true
closeErr := access.close()
closed = true
if closeErr != nil {
return sources, []Diagnostic{importDiagnostic(CodeImportRead, "configuration root could not be closed after reading the selected overlay", nil)}
}
@@ -126,12 +130,12 @@ func loadSelectedOverlayInto(source Source, context *FilesystemContext, main par
return sources, nil
}
func readOverlayFile(root *os.Root, relative, sourceID string, remaining int64) ([]byte, *Diagnostic) {
func readOverlayFile(access *filesystemAccess, name, sourceID string, remaining int64) ([]byte, *Diagnostic) {
limit := min(int64(maxSourceBytes), remaining)
if limit < 0 {
limit = 0
}
data, failure := readRegularFile(relative, root.Stat, root.Open, limit)
data, failure := readRegularFile(name, access.stat, access.open, limit)
if failure != nil {
value := sourceReadDiagnostic(failure, sourceID, CodeOverlayLimitExceeded, "selected overlay exceeds a source or aggregate byte limit")
return nil, &value