Skip to main content

Workspace

Struct Workspace 

Source
pub struct Workspace { /* private fields */ }
Expand description

A named set of per-repo graphs, each opened on demand and cached. Cheap to hold: the stores are small SQLite files opened lazily; the caller (a server) holds the one expensive model. The registry is reloadable in place.

Implementations§

Source§

impl Workspace

Source

pub fn single(name: impl Into<String>, store: Store) -> Self

A single-project workspace over an already-open store, named name. This is the single-repo serve default and the test constructor; a bare (no-project) call resolves to it. Not reloadable (no repo paths).

Source

pub fn from_stores<I, S>(stores: I) -> Self
where I: IntoIterator<Item = (S, Store)>, S: Into<String>,

A workspace over several already-open stores, one per named project — the in-memory counterpart of Workspace::from_repo_paths (which opens each project’s graph.db from disk lazily). Used for multi-repo serving of pre-built stores and for tests. With exactly one project it becomes the default (as Workspace::single); with several, a bare (no-project) call is ambiguous. Not reloadable (no repo paths).

Source

pub fn from_repo_paths<I, P>(paths: I) -> Result<Self, WorkspaceError>
where I: IntoIterator<Item = P>, P: AsRef<Path>,

Build a workspace from repo directories: each is git-discovered, named after its working-tree directory (collisions get a -2, -3, … suffix), and its graph.db opened lazily. With exactly one repo, that repo is the default project.

§Errors

WorkspaceError::Git if a path is not inside a git repository, or WorkspaceError::Empty if paths resolves to no repos.

Source

pub fn from_named_dbs<I>(dbs: I) -> Self
where I: IntoIterator<Item = (String, PathBuf)>,

Build a workspace from explicit (project name, graph.db path) pairs, without git discovery — used where the names and store locations are already known (WorkspaceSet construction re-uses the CLI’s discovery upstream, and tests build synthetic registries). Names are taken verbatim (deduplicate before calling if a collision is possible); with exactly one pair, that project is the default.

Source

pub fn member_dbs(&self) -> Vec<PathBuf>

The graph.db paths of the workspace’s lazily-opened (Path) projects, in stable name order. Pre-opened (single) projects carry no path and are omitted. Used by WorkspaceSet::containing to find which workspace holds a given repo.

Source

pub fn project_root( &self, project: Option<&str>, ) -> Result<Option<PathBuf>, WorkspaceError>

The working-tree root of project’s repository, resolving project the same way Workspace::with_store does (so None means the default project).

This exists so a caller can read that repository’s own configuration rather than the invoking process’s. The rule, following ADR-0009’s per-repo [[links]] resolution: a repository’s own config governs how it is scanned, whoever is asking. Without it, a server started in repo A answers questions about repo B using A’s settings — and B’s own [debt] ignore never applies, so the API and B’s CLI disagree about B.

Returns Ok(None) when the project’s store was handed over pre-opened (Workspace::single / Workspace::from_stores) or registered by graph.db path alone (Workspace::from_named_dbs): there is no repository on disk to consult, and the caller falls back to its own configuration.

§Errors

WorkspaceError::UnknownProject / WorkspaceError::AmbiguousProject as Workspace::resolve, or WorkspaceError::Poisoned.

Source

pub fn with_on_open( self, hook: Arc<dyn Fn(&Path) -> Result<(), String> + Send + Sync>, ) -> Self

Set a first-open hook (serve --sync-on-access): before a project’s store is opened for the first time, hook is run against its graph.db path to (re)build it. Applies to lazily-opened Path projects; a pre-opened single store is already loaded, so the hook does not fire for it.

Source

pub fn reload_from<I, P>(&self, paths: I) -> Result<Vec<String>, WorkspaceError>
where I: IntoIterator<Item = P>, P: AsRef<Path>,

Rebuild the registry from a fresh set of repo paths: added repos become available, removed ones are dropped (and their cached store evicted), and still-present ones keep their warm connection. Returns the new project names. Use this to reload a running server (e.g. on SIGHUP) without a restart. A single-project pre-opened workspace (Workspace::single) has no repo paths, so reloading it simply replaces it with the given repos.

§Errors

As Workspace::from_repo_paths.

Source

pub fn names(&self) -> Vec<String>

The registered project names, in stable order.

Source

pub fn is_multi(&self) -> bool

Whether the workspace holds more than one project (so project selection is meaningful to expose to callers/tools).

Source

pub fn resolve(&self, project: Option<&str>) -> Result<String, WorkspaceError>

Resolve project (or the default) to a concrete project name.

§Errors

WorkspaceError::UnknownProject if named but absent, WorkspaceError::AmbiguousProject if omitted with several projects, or WorkspaceError::Empty if there are none.

Source

pub fn with_store<R>( &self, project: Option<&str>, f: impl FnOnce(&Store) -> R, ) -> Result<R, WorkspaceError>

Run f with the resolved project’s store (opened and cached on first use). The store lock is held only for f, never across an .await.

§Errors

As Workspace::resolve, plus WorkspaceError::NoGraph if the store file is absent, WorkspaceError::Store on open failure, or WorkspaceError::Poisoned if a lock was poisoned.

Source

pub fn with_store_mut<R>( &self, project: Option<&str>, f: impl FnOnce(&mut Store) -> R, ) -> Result<R, WorkspaceError>

Like Workspace::with_store, but hands f a mutable store so it can persist into the graph (e.g. Store::apply_import_layer). The store lock is held only for f, never across an .await. Backs the explorer’s links/write endpoint, which materialises the inferred cross-repo links into a spoke’s graph as a durable import layer.

§Errors

As Workspace::with_store.

Source

pub fn resolve_qualified( &self, qualified: &str, ) -> Result<Option<Node>, WorkspaceError>

Resolve a project-qualified key "<project>::<key>" to its node across the workspace, opening the target project on demand (ADR-0009). Ok(None) means the key is well-formed and the project exists but the node does not — i.e. cross-repo drift (a removed or renamed target). Errors distinguish the other failure modes so a caller can report them precisely: WorkspaceError::Unqualified (not in <project>::<key> form), WorkspaceError::UnknownProject (target repo not in the workspace), WorkspaceError::NoGraph (target repo unsynced).

§Errors

As above, plus WorkspaceError::Store / WorkspaceError::Poisoned.

Source

pub fn follow_external_ref( &self, node: &Node, ) -> Result<Option<Node>, WorkspaceError>

Follow an external-ref placeholder node to the real node it stands for, resolving its project-qualified target across the workspace (ADR-0009). An external-ref lives in a spoke’s store as a local stand-in for a node in the hub’s store (see crate::external_ref_node); this walks it through to the hub. Ok(None) means either node is not an external-ref, or its target no longer resolves — cross-repo drift (a removed or renamed hub key). Errors distinguish the other failure modes, as Workspace::resolve_qualified.

§Errors

As Workspace::resolve_qualified.

Source

pub fn follow_definition( &self, qualified: &str, ) -> Result<Follow, WorkspaceError>

Follow a project-qualified cross-repo target to the most specific definition it names — the follow-the-link hop that turns a click on a spoke’s app-key target into a jump to the hub node that defines it.

Workspace::resolve_qualified lands on the raw hub node a spoke points at, which for a config override is the hub’s config_key node (e.g. cfgkey:config.toml#serve.addr), not the Rust struct that declares the setting. This method adds the net-new config_key → struct bridge: when the resolved node is a config key whose dotted path maps — with confidence — to exactly one hub struct and one of its named fields, it returns that struct as the jump target (Follow::StructField, carrying the matched field name). Otherwise it returns the resolved node unchanged (Follow::Node) — a config key we could not bridge, or any non-config target (e.g. an authored [[links]] that already points at a symbol). A well-formed target whose node is gone is Follow::Drift.

The bridge is deliberately conservative (see [bridge_config_key]): it fires only on a unique match of both an independent section→struct-name signal and a field-presence signal, so it never jumps to a wrong node — an ambiguous or unmatched key falls back to the config-key node.

§Errors

As Workspace::resolve_qualified (a well-formed but unhosted / unsynced target project still errors; a resolved-but-missing node is Drift).

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.