Sled & CGI error handling
Diff
src/git_cgi.rs | 19 ++++++++++++++-----
src/syntax_highlight.rs | 4 +---
src/database/indexer.rs | 12 +++++++++---
src/methods/index.rs | 7 ++++---
src/methods/repo.rs | 15 ++++++++++-----
src/database/schema/repository.rs | 20 ++++++++++++--------
6 files changed, 44 insertions(+), 33 deletions(-)
@@ -1,25 +1,30 @@
use anyhow::{bail, Context, Result};
use axum::body::{boxed, Body};
use axum::http::header::HeaderName;
use axum::http::HeaderValue;
use axum::response::Response;
use httparse::Status;
use std::str::FromStr;
pub fn cgi_to_response(buffer: &[u8]) -> Response {
pub fn cgi_to_response(buffer: &[u8]) -> Result<Response> {
let mut headers = [httparse::EMPTY_HEADER; 10];
let (body_offset, headers) = httparse::parse_headers(buffer, &mut headers)
.unwrap()
.unwrap();
let (body_offset, headers) = match httparse::parse_headers(buffer, &mut headers)? {
Status::Complete(v) => v,
Status::Partial => bail!("Git returned a partial response over CGI"),
};
let mut response = Response::new(boxed(Body::from(buffer[body_offset..].to_vec())));
for header in headers {
response.headers_mut().insert(
HeaderName::from_str(header.name).unwrap(),
HeaderValue::from_bytes(header.value).unwrap(),
HeaderName::from_str(header.name)
.context("Failed to parse header name from Git over CGI")?,
HeaderValue::from_bytes(header.value)
.context("Failed to parse header value from Git over CGI")?,
);
}
response
Ok(response)
}
@@ -18,9 +18,7 @@
ClassedHTMLGenerator::new_with_class_style(syntax, self.syntax_set, ClassStyle::Spaced);
for line in LinesWithEndings::from(code) {
html_generator
.parse_html_for_line_which_includes_newline(line)
.unwrap();
let _ = html_generator.parse_html_for_line_which_includes_newline(line);
}
format!(
@@ -21,8 +21,9 @@
for repository in discovered {
let relative = get_relative_path(scan_path, &repository);
let id =
Repository::open(db, relative).map_or_else(|| RepositoryId::new(db), |v| v.get().id);
let id = Repository::open(db, relative)
.unwrap()
.map_or_else(|| RepositoryId::new(db), |v| v.get().id);
let name = relative.file_name().unwrap().to_string_lossy();
let description = std::fs::read(repository.join("description")).unwrap_or_default();
let description = Some(String::from_utf8_lossy(&description)).filter(|v| !v.is_empty());
@@ -39,7 +40,7 @@
}
fn update_repository_reflog(scan_path: &Path, db: &sled::Db) {
for (relative_path, db_repository) in Repository::fetch_all(db) {
for (relative_path, db_repository) in Repository::fetch_all(db).unwrap() {
let git_repository = git2::Repository::open(scan_path.join(&relative_path)).unwrap();
for reference in git_repository.references().unwrap() {
@@ -59,7 +60,10 @@
info!("Refreshing indexes");
let commit_tree = db_repository.get().commit_tree(db, &reference_name);
let commit_tree = db_repository
.get()
.commit_tree(db, &reference_name)
.unwrap();
if let (Some(latest_indexed), Ok(latest_commit)) =
(commit_tree.fetch_latest_one(), reference.peel_to_commit())
@@ -1,3 +1,4 @@
use anyhow::Context;
use std::collections::BTreeMap;
use askama::Template;
@@ -14,12 +15,12 @@
pub repositories: BTreeMap<Option<String>, Vec<&'a Repository<'a>>>,
}
pub async fn handle(Extension(db): Extension<sled::Db>) -> Response {
pub async fn handle(Extension(db): Extension<sled::Db>) -> Result<Response, super::repo::Error> {
let mut repositories: BTreeMap<Option<String>, Vec<&Repository<'_>>> = BTreeMap::new();
let fetched = tokio::task::spawn_blocking(move || Repository::fetch_all(&db))
.await
.unwrap();
.context("Failed to join Tokio task")??;
for (k, v) in &fetched {
let mut split: Vec<_> = k.split('/').collect();
@@ -30,5 +31,5 @@
k.push(v.get());
}
into_response(&View { repositories })
Ok(into_response(&View { repositories }))
}
@@ -1,3 +1,4 @@
use anyhow::Context;
use std::{
fmt::{Debug, Display, Formatter},
io::Write,
@@ -175,8 +176,9 @@
let open_repo = git.repo(repository_path).await?;
let refs = open_repo.refs().await?;
let repository = crate::database::schema::repository::Repository::open(&db, &*repo).unwrap();
let commit_tree = repository.get().commit_tree(&db, "refs/heads/master");
let repository = crate::database::schema::repository::Repository::open(&db, &*repo)?
.context("Repository does not exist")?;
let commit_tree = repository.get().commit_tree(&db, "refs/heads/master")?;
let commits = commit_tree.fetch_latest(11, 0).await;
let commit_list = commits.iter().map(Yoke::get).collect();
@@ -237,8 +239,9 @@
let offset = query.offset.unwrap_or(0);
let reference = format!("refs/heads/{}", query.branch.as_deref().unwrap_or("master"));
let repository = crate::database::schema::repository::Repository::open(&db, &*repo).unwrap();
let commit_tree = repository.get().commit_tree(&db, &reference);
let repository = crate::database::schema::repository::Repository::open(&db, &*repo)?
.context("Repository does not exist")?;
let commit_tree = repository.get().commit_tree(&db, &reference)?;
let mut commits = commit_tree.fetch_latest(101, offset).await;
let next_offset = if commits.len() == 101 {
@@ -277,7 +280,7 @@
.output()
.unwrap();
Ok(crate::git_cgi::cgi_to_response(&out.stdout))
Ok(crate::git_cgi::cgi_to_response(&out.stdout)?)
}
pub async fn handle_git_upload_pack(
@@ -299,7 +302,7 @@
child.stdin.as_mut().unwrap().write_all(&body).unwrap();
let out = child.wait_with_output().unwrap();
Ok(crate::git_cgi::cgi_to_response(&out.stdout))
Ok(crate::git_cgi::cgi_to_response(&out.stdout)?)
}
#[derive(Template)]
@@ -1,6 +1,7 @@
use crate::database::schema::commit::CommitTree;
use crate::database::schema::prefixes::TreePrefix;
use crate::database::schema::Yoked;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use sled::IVec;
use std::borrow::Cow;
@@ -31,7 +32,7 @@
pub type YokedRepository = Yoked<Repository<'static>>;
impl Repository<'_> {
pub fn fetch_all(database: &sled::Db) -> BTreeMap<String, YokedRepository> {
pub fn fetch_all(database: &sled::Db) -> Result<BTreeMap<String, YokedRepository>> {
database
.scan_prefix([TreePrefix::Repository as u8])
.filter_map(Result::ok)
@@ -45,10 +46,9 @@
let value = Box::new(value);
let value =
Yoke::try_attach_to_cart(value, |data: &IVec| bincode::deserialize(data))
.unwrap();
Yoke::try_attach_to_cart(value, |data: &IVec| bincode::deserialize(data))?;
(key, value)
Ok((key, value))
})
.collect()
}
@@ -62,10 +62,10 @@
.unwrap();
}
pub fn open<P: AsRef<Path>>(database: &sled::Db, path: P) -> Option<YokedRepository> {
pub fn open<P: AsRef<Path>>(database: &sled::Db, path: P) -> Result<Option<YokedRepository>> {
database
.get(TreePrefix::repository_id(path))
.unwrap()
.context("Failed to open indexed repository")?
.map(|value| {
@@ -73,17 +73,17 @@
let value = Box::new(value);
Yoke::try_attach_to_cart(value, |data: &IVec| bincode::deserialize(data))
.context("Failed to deserialise indexed repository")
})
.transpose()
.unwrap()
}
pub fn commit_tree(&self, database: &sled::Db, reference: &str) -> CommitTree {
pub fn commit_tree(&self, database: &sled::Db, reference: &str) -> Result<CommitTree> {
let tree = database
.open_tree(TreePrefix::commit_id(self.id, reference))
.unwrap();
.context("Failed to open commit tree")?;
CommitTree::new(tree)
Ok(CommitTree::new(tree))
}
}