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
impl Core
Sourcepub fn start(spec: CoreSpec) -> Core
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.
Sourcepub fn refresh(&self, order: &[EntityKey]) -> Generation
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.
Sourcepub fn refresh_all(&self) -> Generation
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.
Sourcepub fn rederive_default_branches(&self, keys: &[EntityKey]) -> Generation
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.
Sourcepub fn probe_now(&self, key: &EntityKey) -> EntityState
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.
Sourcepub fn snapshot(&self) -> Snapshot
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.
Sourcepub fn try_settle(&self, within: Duration) -> Result<Snapshot, Snapshot>
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.
Sourcepub fn delete_risk(&self, key: &EntityKey) -> Result<DeleteRisk, ProbeError>
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.
Sourcepub fn worktree_admin_dir(&self, key: &EntityKey) -> Result<PathBuf, ProbeError>
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.
Sourcepub fn linked_worktree_paths(
&self,
key: &EntityKey,
) -> Result<Vec<PathBuf>, ProbeError>
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”).
Sourcepub fn ignored_directories_for_deletion(
&self,
path: &Path,
) -> Result<Vec<PathBuf>, ProbeError>
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.
Sourcepub fn attempt_auto_update(&self, key: &EntityKey) -> AutoUpdateAttempt
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.
Sourcepub fn run_action_for_entity_blocking(
&self,
action: &ActionSpec,
key: &EntityKey,
) -> Option<ActionReceipt>
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.
Sourcepub fn management_handle(&self) -> ManagementHandle
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).
Sourcepub fn dismiss(&self, key: &EntityKey)
pub fn dismiss(&self, key: &EntityKey)
Drops one entity from the table, cancelling any probe in flight against it.
Sourcepub fn operable_count(&self, order: &[EntityKey]) -> usize
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.
Sourcepub fn vanished_count(&self) -> usize
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.
Sourcepub fn applicability(&self, order: &[EntityKey], when: &Filter) -> Applicability
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.
Sourcepub fn action_running(&self) -> bool
pub fn action_running(&self) -> bool
Sourcepub fn refresh_running(&self) -> bool
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.
Sourcepub fn run_action(&self, action: ActionSpec, order: &[EntityKey]) -> bool
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”).
Sourcepub fn hold_action(&self)
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.
Sourcepub fn continue_action(&self)
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.
Sourcepub fn stop_action(&self)
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.
Sourcepub fn pause(&self)
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.
Sourcepub fn resume(&self)
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.
Sourcepub fn discovery_warning(&self) -> Option<String>
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.
Sourcepub fn fetch_failures(&self) -> FetchFailures
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.
Sourcepub fn set_show_submodules(&self, show_submodules: bool)
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.
Sourcepub fn record_own_work(
&self,
label: &str,
results: &[(EntityKey, OwnWork, Duration)],
)
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.
Sourcepub fn set_exclusions(&self, overrides: &[RepoOverride])
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
impl Drop for Core
Source§fn drop(&mut self)
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.
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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