mirror of
https://github.com/vhaudiquet/ecrou.git
synced 2026-11-12 22:22:44 +00:00
feat(progress): report uncounted status through the sink
A run blocked on the cache-entry flock was silent: the wait went to the log sink, which renders nowhere by default, so the CLI read as a hang. The Progress trait gains message() - a status line outside the counted-operation protocol, defaulting to a no-op so existing sinks keep compiling - and the flock wait reports what it is waiting for. The CLI renders messages on the active bar and spins one up when no operation is active.
This commit is contained in:
1 parent
89a1028d46
commit
c2e8d82cd3
5 files changed
+42
-7
No files matched your search
@@ -94,9 +94,11 @@ pub(crate) struct EntryLock {
|
||||
}
|
||||
|
||||
impl EntryLock {
|
||||
/// Block until the entry is free. `no_cache` callers skip the
|
||||
/// lock entirely: an explicit fresh download never waits.
|
||||
pub(crate) fn acquire(entry: &Path) -> anyhow::Result<Self> {
|
||||
/// Block until the entry is free, telling the sink what the run
|
||||
/// is waiting on (a silent block reads as a hang). `no_cache`
|
||||
/// callers skip the lock entirely: an explicit fresh download
|
||||
/// never waits.
|
||||
pub(crate) fn acquire(entry: &Path, progress: &dyn Progress) -> anyhow::Result<Self> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let lock_path = entry.with_extension("lock");
|
||||
@@ -120,6 +122,10 @@ impl EntryLock {
|
||||
"waiting for another ecrou run to finish preparing {}",
|
||||
entry.display()
|
||||
);
|
||||
progress.message(&format!(
|
||||
"Waiting for another ecrou run to finish preparing {}",
|
||||
entry.display()
|
||||
));
|
||||
let held = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX) };
|
||||
if held != 0 {
|
||||
return Err(anyhow::Error::from(std::io::Error::last_os_error())
|
||||
|
||||
@@ -19,7 +19,9 @@ pub enum Unit {
|
||||
///
|
||||
/// Operations are sequential: `begin` starts the next operation (any
|
||||
/// previous one is implicitly over), `advance` counts completed units,
|
||||
/// `finish` marks its end. Sinks must be callable from any thread.
|
||||
/// `finish` marks its end. `message` reports uncounted status outside
|
||||
/// that protocol — a wait, a decision, a retry — when there is nothing
|
||||
/// to count. Sinks must be callable from any thread.
|
||||
pub trait Progress: Send + Sync {
|
||||
/// An operation labelled `label` starts, counting `unit`s; `total`
|
||||
/// is the unit count when known upfront.
|
||||
@@ -30,6 +32,11 @@ pub trait Progress: Send + Sync {
|
||||
|
||||
/// The current operation ended.
|
||||
fn finish(&self);
|
||||
|
||||
/// A status line outside the counted-operation protocol. The
|
||||
/// default discards it; rendering sinks surface it as a spinner
|
||||
/// message, starting one if no operation is active.
|
||||
fn message(&self, _text: &str) {}
|
||||
}
|
||||
|
||||
/// A [`Progress`] sink that discards every event.
|
||||
|
||||
@@ -88,7 +88,8 @@ impl RootfsCache {
|
||||
// One writer per entry: a concurrent run preparing the
|
||||
// same image waits here instead of downloading a second
|
||||
// copy the atomic rename would throw away.
|
||||
let _entry_lock = EntryLock::acquire(&cache_path).map_err(Error::Other)?;
|
||||
let _entry_lock =
|
||||
EntryLock::acquire(&cache_path, progress).map_err(Error::Other)?;
|
||||
// Re-derive the freshness answer under the lock: a
|
||||
// competing run may have filled or refreshed the entry
|
||||
// while we waited.
|
||||
|
||||
Reference in new issue
Block a user