diff --git a/radicle-cli/src/commands/ls.rs b/radicle-cli/src/commands/ls.rs index df88d143..8fbe6484 100644 --- a/radicle-cli/src/commands/ls.rs +++ b/radicle-cli/src/commands/ls.rs @@ -46,7 +46,7 @@ pub fn run(_options: Options, ctx: impl term::Context) -> anyhow::Result<()> { let storage = &profile.storage; let mut table = term::Table::default(); - storage.projects()?.into_iter().for_each(|id| { + storage.repositories()?.into_iter().for_each(|id| { let Ok(repo) = storage.repository(id) else { return }; let Ok((_, head)) = repo.head() else { return }; let Ok(proj) = repo.project_of(profile.id()) else { return }; diff --git a/radicle-httpd/src/api/v1/delegates.rs b/radicle-httpd/src/api/v1/delegates.rs index ce25f58b..d72c91bb 100644 --- a/radicle-httpd/src/api/v1/delegates.rs +++ b/radicle-httpd/src/api/v1/delegates.rs @@ -34,7 +34,7 @@ async fn delegates_projects_handler( let per_page = per_page.unwrap_or(10); let storage = &ctx.profile.storage; let projects = storage - .projects()? + .repositories()? .into_iter() .filter_map(|id| { let Ok(repo) = storage.repository(id) else { return None }; diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index a785ca8d..9eb2385d 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -63,7 +63,7 @@ async fn project_root_handler( let per_page = per_page.unwrap_or(10); let storage = &ctx.profile.storage; let projects = storage - .projects()? + .repositories()? .into_iter() .filter_map(|id| { let Ok(repo) = storage.repository(id) else { return None }; diff --git a/radicle-httpd/src/api/v1/stats.rs b/radicle-httpd/src/api/v1/stats.rs index 79d10cec..873c06e7 100644 --- a/radicle-httpd/src/api/v1/stats.rs +++ b/radicle-httpd/src/api/v1/stats.rs @@ -17,7 +17,7 @@ pub fn router(ctx: Context) -> Router { /// `GET /stats` async fn stats_handler(State(ctx): State) -> impl IntoResponse { let storage = &ctx.profile.storage; - let projects = storage.projects()?.len(); + let projects = storage.repositories()?.len(); Ok::<_, Error>(Json( json!({ "projects": { "count": projects }, "users": { "count": 0 } }), diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 29b70001..d996d47a 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -113,15 +113,15 @@ impl ReadStorage for Storage { } fn inventory(&self) -> Result { - self.projects() + self.repositories() } } impl WriteStorage for Storage { type Repository = Repository; - fn repository(&self, proj: Id) -> Result { - Repository::open(paths::repository(self, &proj), proj) + fn repository(&self, rid: Id) -> Result { + Repository::open(paths::repository(self, &rid), rid) } } @@ -143,20 +143,26 @@ impl Storage { self.path.as_path() } - pub fn projects(&self) -> Result, Error> { - let mut projects = Vec::new(); + pub fn repositories(&self) -> Result, Error> { + let mut repos = Vec::new(); for result in fs::read_dir(&self.path)? { let path = result?; - let id = Id::try_from(path.file_name())?; + let rid = Id::try_from(path.file_name())?; + let repo = self.repository(rid)?; - projects.push(id); + // For performance reasons, we don't do a full repository check here. + if let Err(e) = repo.head() { + log::error!(target: "storage", "Repository {rid} is corrupted: looking up head: {e}"); + continue; + } + repos.push(rid); } - Ok(projects) + Ok(repos) } pub fn inspect(&self) -> Result<(), Error> { - for proj in self.projects()? { + for proj in self.repositories()? { let repo = self.repository(proj)?; for r in repo.raw().references()? {