From 2b4a5d402133bf67324fce1f65579cd6cacf4fb4 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 5 Aug 2023 20:41:23 +0200 Subject: [PATCH] Add somehow::Error wrapping anyhow::Error --- src/config.rs | 4 +++- src/main.rs | 7 ++++--- src/recurring/repo.rs | 29 ++++++++++++++++++----------- src/somehow.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/state.rs | 6 +++--- src/web.rs | 38 +++----------------------------------- 6 files changed, 73 insertions(+), 53 deletions(-) create mode 100644 src/somehow.rs diff --git a/src/config.rs b/src/config.rs index c343455..6b28840 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,6 +5,8 @@ use std::{fs, io::ErrorKind, path::Path, time::Duration}; use serde::Deserialize; use tracing::{debug, info}; +use crate::somehow; + mod default { use std::time::Duration; @@ -74,7 +76,7 @@ pub struct Config { } impl Config { - pub fn load(path: &Path) -> anyhow::Result { + pub fn load(path: &Path) -> somehow::Result { info!(path = %path.display(), "Loading config"); let config = match fs::read_to_string(path) { Ok(str) => toml::from_str(&str)?, diff --git a/src/main.rs b/src/main.rs index c83f73d..1c59f24 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod config; mod recurring; +mod somehow; mod state; mod web; @@ -64,7 +65,7 @@ fn set_up_logging(verbose: u8) { } } -fn load_config(path: Option) -> anyhow::Result<&'static Config> { +fn load_config(path: Option) -> somehow::Result<&'static Config> { let config_path = path.unwrap_or_else(|| { ProjectDirs::from("de", "plugh", "tablejohn") .expect("could not determine home directory") @@ -90,7 +91,7 @@ async fn wait_for_signal() -> io::Result<()> { Ok(()) } -async fn run() -> anyhow::Result<()> { +async fn run() -> somehow::Result<()> { let args = Args::parse(); set_up_logging(args.verbose); @@ -112,7 +113,7 @@ async fn run() -> anyhow::Result<()> { } #[tokio::main] -async fn main() -> anyhow::Result<()> { +async fn main() -> somehow::Result<()> { // Rust-analyzer struggles analyzing code in this function, so the actual // code lives in a different function. run().await diff --git a/src/recurring/repo.rs b/src/recurring/repo.rs index 79bb549..acecfaf 100644 --- a/src/recurring/repo.rs +++ b/src/recurring/repo.rs @@ -9,10 +9,14 @@ use gix::{objs::Kind, traverse::commit::Info, ObjectId, Repository}; use sqlx::{Acquire, SqliteConnection, SqlitePool}; use tracing::{debug, info}; -async fn get_all_commits_from_db(conn: &mut SqliteConnection) -> anyhow::Result> { +use crate::somehow; + +async fn get_all_commits_from_db( + conn: &mut SqliteConnection, +) -> somehow::Result> { let hashes = sqlx::query!("SELECT hash FROM commits") .fetch(conn) - .err_into::() + .err_into::() .and_then(|r| async move { r.hash.parse::().map_err(|e| e.into()) }) .try_collect::>() .await?; @@ -23,11 +27,11 @@ async fn get_all_commits_from_db(conn: &mut SqliteConnection) -> anyhow::Result< fn get_new_commits_from_repo( repo: &Repository, old: &HashSet, -) -> anyhow::Result> { +) -> somehow::Result> { // Collect all references starting with "refs" let mut all_references: Vec = vec![]; for reference in repo.references()?.prefixed("refs")? { - let reference = reference.map_err(|e| anyhow::anyhow!(e))?; + let reference = reference.map_err(|e| somehow::Error(anyhow::anyhow!(e)))?; let id = reference.into_fully_peeled_id()?; // Some repos *cough*linuxkernel*cough* have refs that don't point to @@ -49,7 +53,7 @@ fn get_new_commits_from_repo( Ok(new_commits) } -async fn insert_new_commits(conn: &mut SqliteConnection, new: &[Info]) -> anyhow::Result<()> { +async fn insert_new_commits(conn: &mut SqliteConnection, new: &[Info]) -> somehow::Result<()> { for commit in new { let hash = commit.id.to_string(); sqlx::query!("INSERT OR IGNORE INTO commits (hash) VALUES (?)", hash) @@ -59,7 +63,7 @@ async fn insert_new_commits(conn: &mut SqliteConnection, new: &[Info]) -> anyhow Ok(()) } -async fn insert_new_commit_links(conn: &mut SqliteConnection, new: &[Info]) -> anyhow::Result<()> { +async fn insert_new_commit_links(conn: &mut SqliteConnection, new: &[Info]) -> somehow::Result<()> { for commit in new { let child = commit.id.to_string(); for parent in &commit.parent_ids { @@ -78,14 +82,14 @@ async fn insert_new_commit_links(conn: &mut SqliteConnection, new: &[Info]) -> a Ok(()) } -async fn mark_all_commits_as_old(conn: &mut SqliteConnection) -> anyhow::Result<()> { +async fn mark_all_commits_as_old(conn: &mut SqliteConnection) -> somehow::Result<()> { sqlx::query!("UPDATE commits SET new = 0") .execute(conn) .await?; Ok(()) } -async fn track_main_branch(conn: &mut SqliteConnection, repo: &Repository) -> anyhow::Result<()> { +async fn track_main_branch(conn: &mut SqliteConnection, repo: &Repository) -> somehow::Result<()> { let Some(head) = repo.head_ref()? else { return Ok(()); }; let name = head.inner.name.to_string(); let hash = head.into_fully_peeled_id()?.to_string(); @@ -99,7 +103,10 @@ async fn track_main_branch(conn: &mut SqliteConnection, repo: &Repository) -> an Ok(()) } -async fn update_tracked_refs(conn: &mut SqliteConnection, repo: &Repository) -> anyhow::Result<()> { +async fn update_tracked_refs( + conn: &mut SqliteConnection, + repo: &Repository, +) -> somehow::Result<()> { let tracked_refs = sqlx::query!("SELECT name, hash FROM tracked_refs") .fetch_all(&mut *conn) .await?; @@ -127,7 +134,7 @@ async fn update_tracked_refs(conn: &mut SqliteConnection, repo: &Repository) -> Ok(()) } -async fn update_commit_tracked_status(conn: &mut SqliteConnection) -> anyhow::Result<()> { +async fn update_commit_tracked_status(conn: &mut SqliteConnection) -> somehow::Result<()> { sqlx::query!( " WITH RECURSIVE reachable(hash) AS ( @@ -146,7 +153,7 @@ SET tracked = (hash IN reachable) Ok(()) } -pub async fn update(db: &SqlitePool, repo: &Repository) -> anyhow::Result<()> { +pub async fn update(db: &SqlitePool, repo: &Repository) -> somehow::Result<()> { debug!("Updating repo"); let mut tx = db.begin().await?; let conn = tx.acquire().await?; diff --git a/src/somehow.rs b/src/somehow.rs new file mode 100644 index 0000000..44aa00e --- /dev/null +++ b/src/somehow.rs @@ -0,0 +1,42 @@ +use std::{error, fmt, result}; + +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; + +/// Wrapper around [`anyhow::Error`] that implements additional type classes. +pub struct Error(pub anyhow::Error); + +impl From for Error +where + E: error::Error + Send + Sync + 'static, +{ + fn from(value: E) -> Self { + Self(anyhow::Error::from(value)) + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("500 Internal Server Error\n\n{}", self.0), + ) + .into_response() + } +} + +pub type Result = result::Result; diff --git a/src/state.rs b/src/state.rs index 0b450fa..55528be 100644 --- a/src/state.rs +++ b/src/state.rs @@ -10,7 +10,7 @@ use sqlx::{ }; use tracing::{debug, info}; -use crate::config::Config; +use crate::{config::Config, somehow}; async fn open_db(db_path: &Path) -> sqlx::Result { let options = SqliteConnectOptions::new() @@ -46,7 +46,7 @@ async fn open_db(db_path: &Path) -> sqlx::Result { Ok(pool) } -fn open_repo(repo_path: &Path) -> anyhow::Result { +fn open_repo(repo_path: &Path) -> somehow::Result { info!(path = %repo_path.display(), "Opening repo"); Ok(ThreadSafeRepository::open(repo_path)?) } @@ -63,7 +63,7 @@ impl AppState { config: &'static Config, db_path: &Path, repo_path: &Path, - ) -> anyhow::Result { + ) -> somehow::Result { Ok(Self { config, db: open_db(db_path).await?, diff --git a/src/web.rs b/src/web.rs index 546d537..e6b71f4 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,43 +1,11 @@ mod index; mod r#static; -use std::{error, result}; +use axum::{routing::get, Router, Server}; -use axum::{ - http::StatusCode, - response::{IntoResponse, Response}, - routing::get, - Router, Server, -}; +use crate::{somehow, state::AppState}; -use crate::state::AppState; - -/// Anyhow-like error that also implements [`IntoResponse`]. -pub struct Error(anyhow::Error); - -impl From for Error -where - E: error::Error + Send + Sync + 'static, -{ - fn from(value: E) -> Self { - Self(anyhow::Error::from(value)) - } -} - -impl IntoResponse for Error { - fn into_response(self) -> Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("500 Internal Server Error\n\n{}", self.0), - ) - .into_response() - } -} - -/// Anyhow-like result that also implements [`IntoResponse`]. -pub type Result = result::Result; - -pub async fn run(state: AppState) -> anyhow::Result<()> { +pub async fn run(state: AppState) -> somehow::Result<()> { // TODO Add text body to body-less status codes let app = Router::new()