app.sources.filesystem¶
Filesystem source adapter: ADR files in a directory tree on disk.
Each immediate subdirectory of the configured root is a project
(optionally filtered by scope.projects). ADR files are discovered
recursively under the registration path inside each project, using
the legacy filename pattern (app.domain.titles.is_adr_filename()).
The change token is <mtime_ns>:<size> from os.stat(), so an
unchanged file is never re-read. Directory walks and reads run in a
worker thread via asyncio.to_thread(), since pathlib and
os are blocking.
There is no file:// URL: FilesystemAdapter.fetch() returns
the absolute on-disk path as a human-readable source_url instead.
It is shown only to operators with filesystem access, so a plain path
is the most useful “link” available; author is always None
(the filesystem has no commit/push metadata).
An unreadable or missing root raises SourceNotFoundError
or SourceAccessError from
FilesystemAdapter.list_projects(), which fails the whole poll
(the port contract then deletes nothing). A project’s ADR directory
that is simply absent is not an error (no files); one that exists but
cannot be listed (or whose walk hits an unreadable subdirectory) is
reported as an incomplete document listing for that project only, so
polling preserves its stored records.
Public API: validate_settings(), FilesystemAdapter.
- class app.sources.filesystem.FilesystemAdapter(*, root, path, published_ref, projects=frozenset({}))¶
Bases:
objectReads ADR files from a directory tree on disk.
- Parameters:
root (
Path) – Root directory (one immediate subdirectory per project); may be relative to the process working directory only if the caller already resolved it.path (
str) – ADR path inside each project (POSIX, relative; possibly empty for the project root).published_ref (
str) – Ref label reported for every project (the registration’s configuredpublished_ref; the filesystem has no real refs).projects (
frozenset[str]) – Project names to include; empty means every immediate subdirectory ofroot.
- async list_projects()¶
List the in-scope immediate subdirectories of
root.- Return type:
- Returns:
The listing (always complete; a problem here instead raises).
- Raises:
SourceNotFoundError – If
rootdoes not exist or is not a directory.SourceAccessError – If
rootis not readable.SourceUnavailableError – For any other listing failure.
- async list_documents(project, previous_tokens)¶
List the ADR files of one project.
- Parameters:
project (
SourceProject) – A project fromlist_projects().previous_tokens (
Mapping[str,str|None]) – Stored change token per file path.
- Return type:
- Returns:
The listing;
complete=Falsewith a problem if the project’s ADR directory exists but could not be fully read.
- async fetch(document)¶
Read one document’s exact bytes.
- Parameters:
document (
SourceDocument) – A document fromlist_documents().- Return type:
- Returns:
Its content;
source_urlis the absolute path on disk (there is nofile://URL);authoris alwaysNone.- Raises:
SourceNotFoundError – If the file no longer exists.
SourceAccessError – If it is not readable.
SourceUnavailableError – For any other read failure.
- app.sources.filesystem.validate_settings(settings, env)¶
Validate
rootandscope.projects; bind the adapter factory.No filesystem I/O happens here;
rootis only resolved againstsettings.base_dirwhen relative.- Parameters:
settings (
SourceSettings) – Common settings plusoptions(root) andscope(projects, optional).env (
Mapping[str,str]) – Unused; the filesystem adapter needs no secrets.
- Return type:
- Returns:
The binding.
- Raises:
app.sources.port.SourceConfigError – If
rootorscopeare invalid.