Option C Tools
Loading...
Searching...
No Matches
workspace Namespace Reference

Classes

class  WorkspaceError
class  Subproject
class  Workspace

Functions

Workspace load_workspace (Path root)
Path|None find_workspace_root (Path start)
tuple[bool, str] _validate_workspace_pattern (object pattern)
re.Pattern[str] _glob_to_regex (str pattern)
bool matches_workspace_files (str rel_path, tuple[str,...] patterns)
Subproject|None assign_to_subproject (Path file_path, Workspace workspace)

Variables

str WORKSPACE_MANIFEST = ".option_c_workspace.json"
str _SCHEMA_VERSION = "1.0"
tuple _VALID_PROFILES = ("proto", "compact", "strict")
str _DEFAULT_WORKSPACE_PROFILE = "compact"
re _VALID_WORKSPACE_PATTERN_RE

Detailed Description

Purpose
-------
Workspace (monorepo) support for OCT (F1, leanest first cut). A
workspace is a directory containing a ``.option_c_workspace.json``
manifest and one or more Option C subprojects. ``oct git`` commands
invoked from a workspace root may operate on the entire repo without
the ``--root-dir <subproj> --allow-outside-project`` escape hatch
required pre-F1.

Responsibilities
----------------
- Define :class:`Workspace` — the loaded representation of the
  manifest.
- Provide :func:`load_workspace` — read and validate the manifest at
  ``<root>/.option_c_workspace.json``.
- Provide :func:`find_workspace_root` — walk upward from a starting
  directory to locate the nearest workspace manifest.
- Be intentionally conservative: invalid manifests raise
  :class:`WorkspaceError` rather than degrading silently.

Diagnostics
-----------
Domain: WORKSPACE
Levels:
    L1 — errors (invalid manifest, IO failure)
    L2 — lifecycle (load start / end)
    L3 — details (resolved subproject paths)

Contracts
---------
- This module imports nothing from ``oct.git`` or ``oct.cli``; it sits
  beneath them in the dependency graph.
- Manifest schema is JSON-only (no TOML); the file is small enough
  that adding a TOML parser is unwarranted.
- Subproject paths in the manifest are interpreted relative to the
  workspace root. Absolute paths in the manifest are rejected.
- F1 fan-out (v0.25.0): the manifest now also carries
  ``workspace_profile`` (default ``"compact"``), ``workspace_files``
  (gitignore-style globs of files owned by the workspace itself
  rather than any subproject), and ``ignore_at_workspace_scope``
  (extra ignore patterns applied at the workspace ``.gitignore``).
  All three are optional with documented defaults.

Function Documentation

◆ _glob_to_regex()

re.Pattern[str] workspace._glob_to_regex ( str pattern)
protected
Compile a gitignore-style glob to a regex.

Supports::

    *   matches any sequence of chars within one path segment (no /)
    **  matches across path segments, including /
    ?   matches a single non-/ char
    []  literal char class (treated character-by-character)

Patterns are anchored: the resulting regex must match the entire
relative path. Caching is global and unbounded — the working set
of patterns per session is small and stable.

Definition at line 388 of file workspace.py.

Here is the caller graph for this function:

◆ _validate_workspace_pattern()

tuple[bool, str] workspace._validate_workspace_pattern ( object pattern)
protected
Return ``(valid, message)`` for a workspace_files / ignore pattern.

Mirrors ``oct.git.policy.validate_ignore_pattern`` so the manifest
surface is held to the same safety bar as ``oct git ignore``: no
negation, no absolute paths, no shell metacharacters, no newlines.

Definition at line 360 of file workspace.py.

Here is the caller graph for this function:

◆ assign_to_subproject()

Subproject | None workspace.assign_to_subproject ( Path file_path,
Workspace workspace )
Return the subproject containing *file_path*, or ``None``.

Uses longest-path-prefix match so nested subprojects (rare)
resolve to the deepest match. The returned :class:`Subproject` is
one of ``workspace.subprojects`` (identity-comparable). Returns
``None`` when *file_path* falls outside every subproject — the
caller then decides whether the file matches *workspace_files*
or should be dropped.

Performance: O(N subprojects) per call; N is bounded by manifest
size and is small in practice.

Definition at line 447 of file workspace.py.

◆ find_workspace_root()

Path | None workspace.find_workspace_root ( Path start)
Walk upward from *start* to locate a workspace manifest.

Returns the workspace root, or ``None`` when no manifest is found
by the time the filesystem root is reached.

Definition at line 331 of file workspace.py.

◆ load_workspace()

Workspace workspace.load_workspace ( Path root)
Load and validate the workspace manifest at ``<root>``.

Parameters
----------
root
    Path to the workspace root (the directory containing
    ``.option_c_workspace.json``).

Returns
-------
:class:`Workspace`

Raises
------
WorkspaceError
    If the manifest is missing, malformed, or contains invalid
    subproject paths.

Definition at line 144 of file workspace.py.

Here is the call graph for this function:

◆ matches_workspace_files()

bool workspace.matches_workspace_files ( str rel_path,
tuple[str, ...] patterns )
Return True if *rel_path* matches any *patterns* glob.

*rel_path* must be a forward-slash POSIX-style relative path
(e.g. ``"docs/README.md"``). Backslashes — common on Windows —
must be normalised by the caller.

Definition at line 429 of file workspace.py.

Here is the call graph for this function:

Variable Documentation

◆ _DEFAULT_WORKSPACE_PROFILE

str workspace._DEFAULT_WORKSPACE_PROFILE = "compact"
protected

Definition at line 72 of file workspace.py.

◆ _SCHEMA_VERSION

str workspace._SCHEMA_VERSION = "1.0"
protected

Definition at line 65 of file workspace.py.

◆ _VALID_PROFILES

tuple workspace._VALID_PROFILES = ("proto", "compact", "strict")
protected

Definition at line 68 of file workspace.py.

◆ _VALID_WORKSPACE_PATTERN_RE

re workspace._VALID_WORKSPACE_PATTERN_RE
protected
Initial value:
1= re.compile(
2 r"^[A-Za-z0-9_./*?\‍[\‍]\-]+$",
3)

Definition at line 355 of file workspace.py.

◆ WORKSPACE_MANIFEST

str workspace.WORKSPACE_MANIFEST = ".option_c_workspace.json"

Definition at line 62 of file workspace.py.