Expose native filesystem sources through public loading API
This commit is contained in:
@@ -12,13 +12,14 @@ ConfigKit exposes opaque sources through these constructors:
|
||||
| Constructor | Current contract |
|
||||
| --- | --- |
|
||||
| `File(path)` | Requires a nonempty path, opens a regular file for each consumption, and closes only the library-owned file handle. Missing, inaccessible, unreadable, directory, and other nonregular inputs fail. |
|
||||
| `NewFilesystem(label, filesystem).File(name)` | Borrows a caller-owned `fs.FS` under a safe nonempty display label. `name` must be a non-root slash-relative `fs.ValidPath`. Each load reopens the selected regular file; copies of the `Filesystem` preserve namespace identity. Separate constructors create separate namespaces even for the same label or filesystem. |
|
||||
| `Bytes(label, data)` | Requires a nonempty, non-secret diagnostic label and snapshots bytes during construction. Later caller mutation cannot affect the source. |
|
||||
| `Reader(label, input)` | Requires a nonempty, non-secret label and non-nil reader. The reader is claimed once across all copies of the source, consumed but never closed, and cannot be reused. |
|
||||
| `NoSource()` | Selects defaults-only loading, creates no source record, and marks no paths explicit. |
|
||||
|
||||
The zero `Source` is invalid. Constructor argument failures are retained inside the
|
||||
opaque source and become safe structured diagnostics when the source is consumed.
|
||||
File sources can observe file changes between consumptions; byte sources cannot.
|
||||
File and filesystem sources can observe changes between consumptions; byte sources cannot.
|
||||
|
||||
Each source is limited to 8 MiB. A load using imports or an active overlay is limited
|
||||
to 64 MiB across all accepted sources, 1,024 accepted sources, 64 active import
|
||||
@@ -50,7 +51,7 @@ validate options → parse the selected source → traverse/compose enabled impo
|
||||
→ snapshot configuration and metadata
|
||||
```
|
||||
|
||||
`File`, `Bytes`, and `Reader` each contribute the first base source with deterministic
|
||||
`File`, `Filesystem.File`, `Bytes`, and `Reader` each contribute the first base source with deterministic
|
||||
ID `source-1`; enabled imports continue in depth-first order as `source-2` onward.
|
||||
`NoSource` skips parsing, supplies an absent version to a configured version checker,
|
||||
contributes no source, and continues through defaults, decode, and projection. A
|
||||
@@ -66,7 +67,11 @@ disabled.
|
||||
|
||||
Every source, options, schema, version, defaults, decode, resolution, or validation
|
||||
failure returns a nil result and a `*LoadError`. Successful results contain caller-owned `Config`, detached
|
||||
`Metadata`, a defensive source list, and defensive nonfatal diagnostics. Mutating
|
||||
`Metadata`, a defensive source list, and defensive nonfatal diagnostics. Each source
|
||||
record's `Kind` identifies file, filesystem, bytes, reader, or CLI acquisition
|
||||
independently of its precedence `Layer`. Host file paths remain canonical;
|
||||
filesystem paths are slash-relative within their namespace; synthetic inputs have
|
||||
no path. Mutating
|
||||
the returned configuration or inspection records cannot alter ConfigKit's private
|
||||
snapshot. ConfigKit performs no logging. `Result.WriteEffective` exposes only the
|
||||
frozen redacted projection.
|
||||
@@ -79,7 +84,8 @@ validation, and configuration/metadata snapshotting have completed. A reported
|
||||
load failure returns diagnostics and a nil result, as described above.
|
||||
|
||||
Before returning on success or failure, ConfigKit closes the filesystem handles
|
||||
it opened for loading, including files and directory/root handles. The returned
|
||||
it opened for loading, including files and directory/root handles. Caller-owned
|
||||
filesystems are borrowed, never closed. The returned
|
||||
configuration and inspection metadata require no close operation and remain
|
||||
usable independently of the source files. A supplied `Reader` remains
|
||||
caller-owned and is never closed by ConfigKit.
|
||||
@@ -582,18 +588,25 @@ walk failures, matched directories, invalid documents, escapes, and repeated tar
|
||||
remain errors. Final candidates are bounded by the remaining source limit before
|
||||
their contents are accumulated.
|
||||
|
||||
The configuration root defaults to a selected file's canonical directory. A file
|
||||
source may supply `FilesystemContext.Root` to widen that root but may not supply
|
||||
`BaseDir`. Whenever byte and reader sources supply filesystem context, they must
|
||||
provide both `BaseDir` and `Root` as absolute existing directories; their diagnostic
|
||||
labels, including URI-looking labels, never imply filesystem paths. The base and
|
||||
selected file must be inside the canonical root. Nonregular targets are rejected before opening to avoid blocking on FIFOs;
|
||||
For host files, the configuration root defaults to the selected file's canonical
|
||||
directory. A host file may supply `FilesystemContext.Root` to widen that root but
|
||||
may not supply `BaseDir` or a native `FS`. Byte and reader inputs with host context
|
||||
must provide both `BaseDir` and `Root` as absolute existing directories.
|
||||
For `Filesystem.File`, the default root is `.` in its namespace and the base is
|
||||
the selected file's directory. An explicit context must use the same `Filesystem`
|
||||
namespace and may set `Root` to contain the file and its base; it may not supply
|
||||
`BaseDir`. Byte and reader inputs with native context provide both `BaseDir` and
|
||||
`Root` as slash-relative `fs.ValidPath` directories in `FS` (`.` means its root),
|
||||
with the base inside the root. Context paths are checked even when imports and
|
||||
overlays are inactive. Diagnostic labels, including URI-looking labels, never
|
||||
imply filesystem paths. Nonregular targets are rejected before opening to avoid blocking on FIFOs;
|
||||
post-open regular-file checks remain in place under the stable-input assumption.
|
||||
ConfigKit canonicalizes symlinks,
|
||||
checks containment with relative paths, and opens the canonical root-relative target
|
||||
through a library-owned root handle. Contained relative or absolute symlink targets
|
||||
are accepted; escapes are rejected. Canonical paths define identity, so hard links at
|
||||
distinct paths remain distinct sources.
|
||||
distinct paths remain distinct sources. Native filesystems use slash-path operations
|
||||
and their own symlink behavior; imports stay in their selected namespace and root.
|
||||
|
||||
An active-stack repeat is `import.cycle` and reports the complete cycle's import
|
||||
sites. A previously visited canonical path is `import.repeated` and reports both
|
||||
|
||||
@@ -312,6 +312,14 @@ everyday checker. No public constructors land until the next stage.
|
||||
|
||||
## Stage 4: Expose native filesystem sources through the facade
|
||||
|
||||
**Completed 2026-09-29.** The root API now exposes reusable native filesystem
|
||||
namespaces, namespace-aware contexts, and source acquisition kinds. Ordinary
|
||||
loads support native files, opt-in imports, selected overlays, and byte/reader
|
||||
contexts while retaining host semantics. Public tests cover embedded fixtures,
|
||||
`fstest.MapFS`, same-label namespace isolation, wrapper copies and reuse,
|
||||
constructor/context diagnostics, and host/CLI source kinds. The everyday checker
|
||||
passed, including public-boundary and documentation checks.
|
||||
|
||||
1. Add `Filesystem`, `NewFilesystem`, `Filesystem.File`, and the additive FS
|
||||
context field at root and engine boundaries. Constructors follow deferred
|
||||
diagnostics; copying the wrapper preserves namespace identity.
|
||||
|
||||
Reference in New Issue
Block a user