Add somehow::Error wrapping anyhow::Error
This commit is contained in:
parent
a5c0552341
commit
2b4a5d4021
6 changed files with 73 additions and 53 deletions
|
|
@ -5,6 +5,8 @@ use std::{fs, io::ErrorKind, path::Path, time::Duration};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
|
use crate::somehow;
|
||||||
|
|
||||||
mod default {
|
mod default {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
@ -74,7 +76,7 @@ pub struct Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load(path: &Path) -> anyhow::Result<Self> {
|
pub fn load(path: &Path) -> somehow::Result<Self> {
|
||||||
info!(path = %path.display(), "Loading config");
|
info!(path = %path.display(), "Loading config");
|
||||||
let config = match fs::read_to_string(path) {
|
let config = match fs::read_to_string(path) {
|
||||||
Ok(str) => toml::from_str(&str)?,
|
Ok(str) => toml::from_str(&str)?,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mod config;
|
mod config;
|
||||||
mod recurring;
|
mod recurring;
|
||||||
|
mod somehow;
|
||||||
mod state;
|
mod state;
|
||||||
mod web;
|
mod web;
|
||||||
|
|
||||||
|
|
@ -64,7 +65,7 @@ fn set_up_logging(verbose: u8) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_config(path: Option<PathBuf>) -> anyhow::Result<&'static Config> {
|
fn load_config(path: Option<PathBuf>) -> somehow::Result<&'static Config> {
|
||||||
let config_path = path.unwrap_or_else(|| {
|
let config_path = path.unwrap_or_else(|| {
|
||||||
ProjectDirs::from("de", "plugh", "tablejohn")
|
ProjectDirs::from("de", "plugh", "tablejohn")
|
||||||
.expect("could not determine home directory")
|
.expect("could not determine home directory")
|
||||||
|
|
@ -90,7 +91,7 @@ async fn wait_for_signal() -> io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run() -> anyhow::Result<()> {
|
async fn run() -> somehow::Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
set_up_logging(args.verbose);
|
set_up_logging(args.verbose);
|
||||||
|
|
@ -112,7 +113,7 @@ async fn run() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> somehow::Result<()> {
|
||||||
// Rust-analyzer struggles analyzing code in this function, so the actual
|
// Rust-analyzer struggles analyzing code in this function, so the actual
|
||||||
// code lives in a different function.
|
// code lives in a different function.
|
||||||
run().await
|
run().await
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,14 @@ use gix::{objs::Kind, traverse::commit::Info, ObjectId, Repository};
|
||||||
use sqlx::{Acquire, SqliteConnection, SqlitePool};
|
use sqlx::{Acquire, SqliteConnection, SqlitePool};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
async fn get_all_commits_from_db(conn: &mut SqliteConnection) -> anyhow::Result<HashSet<ObjectId>> {
|
use crate::somehow;
|
||||||
|
|
||||||
|
async fn get_all_commits_from_db(
|
||||||
|
conn: &mut SqliteConnection,
|
||||||
|
) -> somehow::Result<HashSet<ObjectId>> {
|
||||||
let hashes = sqlx::query!("SELECT hash FROM commits")
|
let hashes = sqlx::query!("SELECT hash FROM commits")
|
||||||
.fetch(conn)
|
.fetch(conn)
|
||||||
.err_into::<anyhow::Error>()
|
.err_into::<somehow::Error>()
|
||||||
.and_then(|r| async move { r.hash.parse::<ObjectId>().map_err(|e| e.into()) })
|
.and_then(|r| async move { r.hash.parse::<ObjectId>().map_err(|e| e.into()) })
|
||||||
.try_collect::<HashSet<_>>()
|
.try_collect::<HashSet<_>>()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
@ -23,11 +27,11 @@ async fn get_all_commits_from_db(conn: &mut SqliteConnection) -> anyhow::Result<
|
||||||
fn get_new_commits_from_repo(
|
fn get_new_commits_from_repo(
|
||||||
repo: &Repository,
|
repo: &Repository,
|
||||||
old: &HashSet<ObjectId>,
|
old: &HashSet<ObjectId>,
|
||||||
) -> anyhow::Result<Vec<Info>> {
|
) -> somehow::Result<Vec<Info>> {
|
||||||
// Collect all references starting with "refs"
|
// Collect all references starting with "refs"
|
||||||
let mut all_references: Vec<ObjectId> = vec![];
|
let mut all_references: Vec<ObjectId> = vec![];
|
||||||
for reference in repo.references()?.prefixed("refs")? {
|
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()?;
|
let id = reference.into_fully_peeled_id()?;
|
||||||
|
|
||||||
// Some repos *cough*linuxkernel*cough* have refs that don't point to
|
// 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)
|
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 {
|
for commit in new {
|
||||||
let hash = commit.id.to_string();
|
let hash = commit.id.to_string();
|
||||||
sqlx::query!("INSERT OR IGNORE INTO commits (hash) VALUES (?)", hash)
|
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(())
|
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 {
|
for commit in new {
|
||||||
let child = commit.id.to_string();
|
let child = commit.id.to_string();
|
||||||
for parent in &commit.parent_ids {
|
for parent in &commit.parent_ids {
|
||||||
|
|
@ -78,14 +82,14 @@ async fn insert_new_commit_links(conn: &mut SqliteConnection, new: &[Info]) -> a
|
||||||
Ok(())
|
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")
|
sqlx::query!("UPDATE commits SET new = 0")
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
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 Some(head) = repo.head_ref()? else { return Ok(()); };
|
||||||
let name = head.inner.name.to_string();
|
let name = head.inner.name.to_string();
|
||||||
let hash = head.into_fully_peeled_id()?.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(())
|
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")
|
let tracked_refs = sqlx::query!("SELECT name, hash FROM tracked_refs")
|
||||||
.fetch_all(&mut *conn)
|
.fetch_all(&mut *conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
@ -127,7 +134,7 @@ async fn update_tracked_refs(conn: &mut SqliteConnection, repo: &Repository) ->
|
||||||
Ok(())
|
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!(
|
sqlx::query!(
|
||||||
"
|
"
|
||||||
WITH RECURSIVE reachable(hash) AS (
|
WITH RECURSIVE reachable(hash) AS (
|
||||||
|
|
@ -146,7 +153,7 @@ SET tracked = (hash IN reachable)
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(db: &SqlitePool, repo: &Repository) -> anyhow::Result<()> {
|
pub async fn update(db: &SqlitePool, repo: &Repository) -> somehow::Result<()> {
|
||||||
debug!("Updating repo");
|
debug!("Updating repo");
|
||||||
let mut tx = db.begin().await?;
|
let mut tx = db.begin().await?;
|
||||||
let conn = tx.acquire().await?;
|
let conn = tx.acquire().await?;
|
||||||
|
|
|
||||||
42
src/somehow.rs
Normal file
42
src/somehow.rs
Normal file
|
|
@ -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<E> From<E> 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<T> = result::Result<T, Error>;
|
||||||
|
|
@ -10,7 +10,7 @@ use sqlx::{
|
||||||
};
|
};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::{config::Config, somehow};
|
||||||
|
|
||||||
async fn open_db(db_path: &Path) -> sqlx::Result<SqlitePool> {
|
async fn open_db(db_path: &Path) -> sqlx::Result<SqlitePool> {
|
||||||
let options = SqliteConnectOptions::new()
|
let options = SqliteConnectOptions::new()
|
||||||
|
|
@ -46,7 +46,7 @@ async fn open_db(db_path: &Path) -> sqlx::Result<SqlitePool> {
|
||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_repo(repo_path: &Path) -> anyhow::Result<ThreadSafeRepository> {
|
fn open_repo(repo_path: &Path) -> somehow::Result<ThreadSafeRepository> {
|
||||||
info!(path = %repo_path.display(), "Opening repo");
|
info!(path = %repo_path.display(), "Opening repo");
|
||||||
Ok(ThreadSafeRepository::open(repo_path)?)
|
Ok(ThreadSafeRepository::open(repo_path)?)
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ impl AppState {
|
||||||
config: &'static Config,
|
config: &'static Config,
|
||||||
db_path: &Path,
|
db_path: &Path,
|
||||||
repo_path: &Path,
|
repo_path: &Path,
|
||||||
) -> anyhow::Result<Self> {
|
) -> somehow::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
config,
|
config,
|
||||||
db: open_db(db_path).await?,
|
db: open_db(db_path).await?,
|
||||||
|
|
|
||||||
38
src/web.rs
38
src/web.rs
|
|
@ -1,43 +1,11 @@
|
||||||
mod index;
|
mod index;
|
||||||
mod r#static;
|
mod r#static;
|
||||||
|
|
||||||
use std::{error, result};
|
use axum::{routing::get, Router, Server};
|
||||||
|
|
||||||
use axum::{
|
use crate::{somehow, state::AppState};
|
||||||
http::StatusCode,
|
|
||||||
response::{IntoResponse, Response},
|
|
||||||
routing::get,
|
|
||||||
Router, Server,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::state::AppState;
|
pub async fn run(state: AppState) -> somehow::Result<()> {
|
||||||
|
|
||||||
/// Anyhow-like error that also implements [`IntoResponse`].
|
|
||||||
pub struct Error(anyhow::Error);
|
|
||||||
|
|
||||||
impl<E> From<E> 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<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
pub async fn run(state: AppState) -> anyhow::Result<()> {
|
|
||||||
// TODO Add text body to body-less status codes
|
// TODO Add text body to body-less status codes
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue