Skip to main content

Core

Struct Core 

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

A running core: its own table, its own dedicated thread, and the rayon pool it shares with the rest of the process for probes.

Construction is start, never a plain constructor, because it spawns; Drop joins every thread it spawned. The public entry points are exactly start, refresh, probe_now, snapshot, try_settle, dismiss, pause, resume, discovery_warning and run_action (see its own doc comment).

Implementations§

Source§

impl Core

Source

pub fn start(spec: CoreSpec) -> Core

Spawns the dedicated thread, starts the first discovery walk on a thread of its own, and returns a running core at once.

The table it returns is empty: discovery lands its rows afterwards, which is what lets a consumer claim the terminal and draw a first frame without waiting out a walk (refresh.md’s “The first frame”). That walk is refresh.md’s “Startup” Generation as well, dispatched over what it found, so a consumer probes its rows by starting a Core and never by asking for a second walk of the same tree. Self::try_settle waits for it the way it waits for any other Generation.

Source

pub fn refresh(&self, order: &[EntityKey]) -> Generation

Starts a new Generation, dispatching a probe for every key in order that the table already knows, in that order. An empty or unknown-only order dispatches nothing and carries no other meaning. Returns immediately: the probes run on rayon’s global pool.

Source

pub fn refresh_all(&self) -> Generation

Starts a new Generation over every entity this Generation’s own discovery leaves in the table, in discovery order.

A Set switch’s Generation, per refresh.md’s “Switching Set”: the caller has just discarded the old Set’s rows, so it has no order to compute and no keys to name. Unlike Self::refresh, which resolves the order the caller handed it, this resolves the order after discovery has run, which is what lets it cover rows the caller could not have named. Startup needs none of this: Self::start’s own walk is that Generation. Returns immediately, the same way refresh does.

Source

pub fn rederive_default_branches(&self, keys: &[EntityKey]) -> Generation

Re-derives default_branch alone for every key in keys already known to the table, in a fresh Generation, per default-branch.md’s “A user-triggered re-derive over the Selection … on demand” and keybindings.md’s b. Unlike Self::refresh, this never re-runs discovery and never touches any other cell on any entity, known or not: a key outside keys is left exactly as it was, and so is every cell but default_branch on a key inside it.

Runs the local chain exactly as any other refresh would, then a handshake-only network probe per distinct common dir among keys (fetch::probe_remote_head): no pack requested and no ref updated, which is “without fetching”. Its answer, once landed on network_default_branch, is what supersede_with_network applies here and on every later probe of that common dir for the life of this Core.

Returns immediately, which is also why a stalled remote has nothing to end it here: the deadline sweep is per entity, not per cell, so this is on the open-questions register rather than closed. The probes run on a plain thread, never rayon’s global pool, for the reason fetch::run_bounded’s own doc comment gives the periodic fetch’s identical choice: a remote blocked on the network for seconds must never take a worker away from the pool every other probe shares.

Source

pub fn probe_now(&self, key: &EntityKey) -> EntityState

Re-probes one entity synchronously against the table’s current Generation, which is what a Launcher return needs before a normal Generation starts. Inserts a fresh entity for an unknown key rather than panicking, since a caller can otherwise only reach this with a key snapshot just handed it.

Source

pub fn snapshot(&self) -> Snapshot

Clones the whole table now, without waiting for anything in flight. Ages every entity’s dirty and state cells into Stale here, on the clone rather than the stored table, so a snapshot stays a pure read: the other staleness writer, poll evidence, does mutate the stored table, because a detected move is itself a fact worth keeping, but elapsed time is not.

Source

pub fn try_settle(&self, within: Duration) -> Result<Snapshot, Snapshot>

Blocks until nothing is in flight or within elapses, then returns a snapshot. The machine-readable consumer’s whole loop.

Ok is a table that actually settled. Err is the wait giving up, carrying the snapshot as it stood at that moment so a caller that means to degrade still has something to degrade with. The two are separate arms rather than one return value because they are separate facts: a half-populated table read as a settled one is a wrong answer, not a late one, and it reads as a defect several steps downstream with nothing left naming the wait.

Source

pub fn delete_risk(&self, key: &EntityKey) -> Result<DeleteRisk, ProbeError>

What deleting key’s working tree destroys, read fresh right now (repo-management.md’s “The confirm gate”). Every one of the three is a git read rather than a fold over this entity’s Cells or over the table: the gate is answering “what will accepting this destroy”, a Cell carries whatever the last Generation left there, and the table is bounded by the active Set’s roots, so a linked Worktree outside them would go unnamed. Both are the wrong tense, or the wrong scope, for a question with no undo.

uncommitted is both halves of “not in a commit”: the index against the working tree (git::dirty_counts) and HEAD against the index (git::staged_changes). The second is the one a git add with no commit lands in, and the one the dirty column deliberately never asks about.

Errors rather than reporting zero when any read fails, so a gate never says “nothing to lose” because it could not look.

Source

pub fn worktree_admin_dir(&self, key: &EntityKey) -> Result<PathBuf, ProbeError>

The administrative directory git worktree remove deletes for key’s own linked Worktree, read fresh right now. Err when key’s own path cannot even be opened as a git repository, which is what “the parent Repo is gone or unreadable” means for a delete on a Worktree row (repo-management.md’s “What delete does to a Worktree”): the caller falls back to removing the working directory alone.

Source

pub fn linked_worktree_paths( &self, key: &EntityKey, ) -> Result<Vec<PathBuf>, ProbeError>

Every linked Worktree’s own working directory pointing into key’s Repo, read fresh right now: what deleting a Repo needs to also remove, since each linked Worktree’s directory sits outside the Repo’s own and is untouched by removing that alone (repo-management.md’s “Deleting a Repo also takes its linked Worktrees with it”).

Source

pub fn ignored_directories_for_deletion( &self, path: &Path, ) -> Result<Vec<PathBuf>, ProbeError>

delete’s phase 1: the ignored directories inside the working tree at path, read fresh right now (repo-management.md’s “Deleting a working tree”). path rather than an EntityKey because a Repo delete runs this once for its own working tree and once more for each linked Worktree Self::linked_worktree_paths names, and only the first of those has a Set row of its own.

Source

pub fn attempt_auto_update(&self, key: &EntityKey) -> AutoUpdateAttempt

Attempts the fast-forward-only auto-update on key’s own Repo, on demand: exactly crate::auto_update::attempt’s own five rules and its own fast-forward, reused rather than a second implementation for the built-in sync action to call by hand (repo-management.md). Read fresh right now, the same tense Self::delete_risk reads in: eligibility can change between the gate and the run, so this is never answered from a Cell.

Source

pub fn run_action_for_entity_blocking( &self, action: &ActionSpec, key: &EntityKey, ) -> Option<ActionReceipt>

Runs action’s own steps against one Entity, on the calling thread, blocking until they finish rather than handing the run off the way Core::run_action’s async fan-out does. A pre or post hook wrapping a built-in (0032) needs the outcome before the built-in can proceed or report, which nothing running off this thread can give in time. Reuses run_action_for_entity, the identical per-step execution run_action’s fan-out gives every entity, so a hook and a configured [[action]] never diverge in what a step means; writes nothing to the table and touches none of run_action’s own state (action_running, action_control), since a hook is a distinct concern from the one fan-out the palette tracks.

None when key names no Entity this table currently knows.

Source

pub fn management_handle(&self) -> ManagementHandle

Vends a ManagementHandle: the Send + 'static seam a management run’s own per-row work moves onto a background thread through, so it stops blocking the caller the way Self::run_action’s own fan-out already moves an Arc<RwLock<Table>> clone onto its own thread (0033).

Source

pub fn dismiss(&self, key: &EntityKey)

Drops one entity from the table, cancelling any probe in flight against it.

Source

pub fn operable_count(&self, order: &[EntityKey]) -> usize

How many of order are operable, i.e. not excluded: Self::run_action’s own first move is the identical partition this method itself calls, so this is the one number a confirm gate and a palette border can both read without either ever drifting from what that first move keeps. Not the final count a run acts on once action.when is Some: Self::applicability narrows this same set further, and Self::run_action itself only ever runs the rows that narrowing proves.

Source

pub fn vanished_count(&self) -> usize

How many Entities in the live table are Vanished. Reads the table in place rather than through Self::snapshot, so a caller needing only the count does not pay for a clone of the whole table and its staleness pass on every frame.

Source

pub fn applicability(&self, order: &[EntityKey], when: &Filter) -> Applicability

How an Action’s when predicate divides the very rows Self::operable_count counts: the identical partition runs first, so an excluded row is subtracted before the predicate ever sees it and when narrows what is left rather than replacing that subtraction (docs/spec/actions.md’s “The Selection and the gate”). A palette calls this ahead of time, to report a count before a choice is even made; Self::run_action runs the identical classification against the identical rows once a choice is confirmed, over ActionSpec::when rather than an argument of its own, so a preview and a real run can never disagree.

The tally lives here rather than in the consumer for that reason alone: partition_operable is this type’s own, so a caller cannot count applicability over a set the run would not act on.

Source

pub fn action_running(&self) -> bool

true while one Action fan-out’s steps are still running, the consumer-facing read of action_running (ADR 0018’s “One Action runs at a time”): what a TUI gates ;, s, 1 to 9 and Ctrl+R against while a run is in flight (ADR 0023).

Source

pub fn refresh_running(&self) -> bool

true while any refresh-shaped dispatch this Core started still owes the table work: a Generation reserved and not yet raised the probes it dispatches, or probes raised and not yet landed, cancelled or timed out. The same gate Core::try_settle blocks on, read here without blocking, so a consumer can report a Refresh’s own progress on screen while it runs rather than waiting for it to finish (refresh.md). Covers refresh, refresh_all, rederive_default_branches, probe_now and the startup walk alike; an Action’s own fan-out never touches this gate, which is what action_running reads instead.

Source

pub fn run_action(&self, action: ActionSpec, order: &[EntityKey]) -> bool

Runs action across every key in order that the table currently knows: each entity’s own steps run in order and stop at that entity’s first failure, exactly as config.md’s “Actions” fixes, with later steps recorded NotRun rather than silently skipped. Cross-entity concurrency is bounded by action.concurrency, on a rayon::ThreadPool this call builds and owns for the run alone, never rayon’s global pool the probe fan-out shares: a step blocked in wait() removes a worker from whichever pool holds it, and the global pool has none to spare without starving a refresh in flight (docs/spec/actions.md’s “The fan-out”). Returns immediately; every step’s own child, and this run’s completion, run off the calling thread.

Returns false and touches nothing if a fan-out is already running: only one runs at a time (ADR 0018’s “One Action runs at a time”), but the spec settles only that the palette goes inert while one is live, never what a second, concurrent call to this seam itself should do. Rejecting outright, rather than queuing, is this call’s own choice: a queue needs its own ordering and cancellation story that no acceptance criterion here asks for.

An entity in order carrying a matching [[repo]] exclude = true (config.md) never runs a step: it receives a Skip::Excluded receipt with an empty step list immediately, the one legitimate producer of Not applicable (docs/spec/actions.md’s “The Selection and the gate”). An unknown key in order (already dismissed, or never discovered) is silently skipped, the same fallback refresh gives one.

action.when, once every excluded row is already subtracted, decides what runs rather than only what a palette reported about it: a row it proves is handed a step, a row it disproves gets a Skip::Inapplicable receipt instead, and a row it cannot settle (a Cell it reads has not settled) gets Skip::Unresolved, since an unprovable row is not a provable one and a run has no basis to touch it either (docs/spec/actions.md’s “The Selection and the gate”, reversing what that paragraph originally decided). None runs every operable row, exactly as before when reached this call.

Starting a run cancels any in-flight Generation outright rather than sharing execution with it, and completion starts exactly one normal Generation over every entity the table currently knows, not only the ones this run touched. Explicitly not done, for the same reason: re-probing each affected entity synchronously first, the way a Launcher return does with Core::probe_now. Both choices, and their measured cost, are ADR 0018’s (“Refreshing around a run”).

Source

pub fn hold_action(&self)

SIGSTOPs every currently live step’s process group in the fan-out run_action started, reversible with Self::continue_action: suspending a run is reversible, where cancelling one is not (docs/spec/actions.md’s “Cancellation and quit”). A no-op while no fan-out is running. Its own verb, kept apart from Self::pause, which stays ignorant of why background work stopped.

Source

pub fn continue_action(&self)

SIGCONTs every currently live step’s process group, undoing Self::hold_action. A no-op while no fan-out is running.

Source

pub fn stop_action(&self)

Cancels the fan-out run_action started: SIGTERM now to every step’s process group still live, SIGKILL after a grace to whichever of those have not exited by then, because SIGTERM is trappable and SIGKILL is not. A step already running when this is called becomes Cancelled; so does a step, or a whole entity’s run, that had not started, which stays distinct from NotRun (docs/spec/actions.md’s “Cancellation and quit”). A no-op while no fan-out is running. Its own verb, kept apart from Self::pause for the same reason Self::hold_action is.

Source

pub fn pause(&self)

Stops all background work: the dedicated thread stops ticking and every probe currently in flight is cancelled. The core is never told why.

Source

pub fn resume(&self)

Restarts the dedicated thread’s ticking. Nothing is queued to fire on resume; a normal Generation is the consumer’s decision, not this call’s.

Source

pub fn discovery_warning(&self) -> Option<String>

The persistent warning a re-run discovery walk leaves behind once it abandons, or None while none has. Never cleared once set, the same as discovery_manual: the Set stays out of the automatic refresh path for the life of this Core. The UI’s shared warning slot polls this every frame, since it can turn from None to Some at any point in the run with no reload involved.

Source

pub fn fetch_failures(&self) -> FetchFailures

The most recently completed periodic-fetch cycle’s own failures, or an empty FetchFailures once every fetch in that cycle succeeded, or the cycle has never run. The UI’s shared warning slot polls this every frame, the same way it polls Self::discovery_warning and Self::vanished_count, since a later cycle can replace this at any point in the run with no reload involved.

Source

pub fn set_show_submodules(&self, show_submodules: bool)

Sets the live show-submodules preference a Generation’s dispatch reads from this point on: whether a Kind::Submodule entity is probed at all (discovery.md’s “Showing Submodules”). Takes effect on the next refresh, dispatches nothing of its own and starts no Generation, which is what makes toggling this instant rather than a rebuild: CoreSpec’s own show_submodules is only this flag’s starting value.

Source

pub fn record_own_work( &self, label: &str, results: &[(EntityKey, OwnWork, Duration)], )

Writes one receipt per row for work Repon did itself, with no child process anywhere in it: what a Management operation leaves behind (repo-management.md’s “Receipts”, docs/spec/actions.md’s OwnWork).

The receipt is built here rather than handed in whole, so a consumer supplies only what Repon did and the words for it: skip stays None, since a refusal is a row that was operated on rather than one of the three ways a row is skipped, running stays None, since the work is already done, and the step count stays one, since the operation is one act rather than an ordered list. label is the operation’s own name and doubles as the single step’s label; the step’s captured output is empty, there being no other program’s screen to quote.

Starts no Generation and dispatches nothing, for the same reason Core::set_exclusions does not: a receipt is something Repon did rather than a reading of the world, so nothing here can make a cell any more or less true. A key the table no longer holds is skipped, the same fallback every key-addressed entry point here gives one.

Source

pub fn set_exclusions(&self, overrides: &[RepoOverride])

Replaces the live exclude half of [[repo]] and re-applies it over every row the table already holds, so the next Core::snapshot answers with the new reading (repo-management.md’s “Writing config”: an ignore takes effect as soon as this call returns).

Starts no Generation, dispatches nothing and rediscovers nothing, for the same reason Core::set_show_submodules does not: exclude decides only whether an operation may reach a row, never what discovery finds or what a probe reads. default_branch, the other key a [[repo]] entry may carry, is a probe input and is deliberately not moved here; it still needs a rebuilt Core.

Trait Implementations§

Source§

impl Drop for Core

Source§

fn drop(&mut self)

Cancels whatever this Core still has in flight, then joins the dedicated thread.

The cancel is what Core::pause already does, for the same reason refresh.md’s “Cancellation” gives: an abandoned Generation is cancelled rather than left to finish, since a Set switch rebuilds the Core and the outgoing one’s fan-out would otherwise contend for the same cores as the incoming one’s. A probe already past its own cancel check still runs to completion on rayon’s global pool, which is shared process-wide infrastructure rather than a thread this core spawned, so it is not joined here.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Core

§

impl !UnwindSafe for Core

§

impl Freeze for Core

§

impl Send for Core

§

impl Sync for Core

§

impl Unpin for Core

§

impl UnsafeUnpin for Core

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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
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 = !

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

fn try_from(value: U) -> Result<T, !>

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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more