From d56e2f90efed3b851db1abaca16e515b5d0931e3 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Thu, 21 Jul 2022 22:54:14 +0100 Subject: [PATCH] Nicer error handling when calling out to git2 --- Cargo.lock | 19 +++++++++++++++++++ Cargo.toml | 2 ++ src/git.rs | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- src/main.rs | 15 ++++++++++++--- src/methods/repo.rs | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 286 insertions(+), 185 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58c6bad..7933fd1 100644 --- a/Cargo.lock +++ a/Cargo.lock @@ -200,6 +200,18 @@ ] [[package]] +name = "axum-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6293dae2ec708e679da6736e857cf8532886ef258e92930f38279c12641628b8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -948,6 +960,12 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -1918,6 +1936,7 @@ "anyhow", "askama", "axum", + "axum-macros", "bat", "bincode", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 2577212..644500c 100644 --- a/Cargo.toml +++ a/Cargo.toml @@ -7,7 +7,9 @@ [dependencies] askama = "0.11" +anyhow = "1.0" axum = "0.5" +axum-macros = "0.2" bat = { version = "0.21", default-features = false, features = ["build-assets"] } bytes = "1.1" bincode = "1.3" diff --git a/src/git.rs b/src/git.rs index 048b73c..631cfaa 100644 --- a/src/git.rs +++ a/src/git.rs @@ -1,8 +1,9 @@ use std::ffi::OsStr; use std::path::Path; use std::{borrow::Cow, fmt::Write, path::PathBuf, sync::Arc, time::Duration}; use crate::syntax_highlight::ComrakSyntectAdapter; +use anyhow::{Context, Result}; use bytes::{Bytes, BytesMut}; use comrak::{ComrakOptions, ComrakPlugins}; use git2::{ @@ -46,19 +47,20 @@ impl Git { #[instrument(skip(self))] - pub async fn repo(self: Arc, repo_path: PathBuf) -> Arc { + pub async fn repo(self: Arc, repo_path: PathBuf) -> Result> { let repo = tokio::task::spawn_blocking({ let repo_path = repo_path.clone(); - move || git2::Repository::open(repo_path).unwrap() + move || git2::Repository::open(repo_path) }) .await - .unwrap(); + .context("Failed to join Tokio task")? + .context("Failed to open repository")?; - Arc::new(OpenRepository { + Ok(Arc::new(OpenRepository { git: self, cache_key: repo_path, repo: Mutex::new(repo), - }) + })) } } @@ -74,59 +76,72 @@ path: Option, tree_id: Option<&str>, branch: Option, - ) -> PathDestination { - let tree_id = tree_id.map(Oid::from_str).transpose().unwrap(); + ) -> Result { + let tree_id = tree_id + .map(Oid::from_str) + .transpose() + .context("Failed to parse tree hash")?; tokio::task::spawn_blocking(move || { let repo = self.repo.lock(); let mut tree = if let Some(tree_id) = tree_id { - repo.find_tree(tree_id).unwrap() + repo.find_tree(tree_id) + .context("Couldn't find tree with given id")? } else if let Some(branch) = branch { - let branch = repo.find_branch(&branch, BranchType::Local).unwrap(); - branch.get().peel_to_tree().unwrap() + let branch = repo.find_branch(&branch, BranchType::Local)?; + branch + .get() + .peel_to_tree() + .context("Couldn't find tree for branch")? } else { - let head = repo.head().unwrap(); - head.peel_to_tree().unwrap() + let head = repo.head()?; + head.peel_to_tree() + .context("Couldn't find tree from HEAD")? }; if let Some(path) = path.as_ref() { - let item = tree.get_path(path).unwrap(); - let object = item.to_object(&repo).unwrap(); + let item = tree.get_path(path).context("Path doesn't exist in tree")?; + let object = item + .to_object(&repo) + .context("Path in tree isn't an object")?; if let Some(blob) = object.as_blob() { - let name = item.name().unwrap().to_string(); - let path = path.clone().join(&name); + // TODO: use Path here instead of a lossy utf8 conv + let name = String::from_utf8_lossy(item.name_bytes()); + let path = path.clone().join(&*name); let extension = path .extension() .or_else(|| path.file_name()) - .unwrap() - .to_string_lossy(); - let content = format_file(blob.content(), &extension, &self.git.syntax_set); - - return PathDestination::File(FileWithContent { + .map(|v| v.to_string_lossy()) + .unwrap_or_else(|| Cow::Borrowed("")); + let content = format_file(blob.content(), &extension, &self.git.syntax_set)?; + + return Ok(PathDestination::File(FileWithContent { metadata: File { mode: item.filemode(), size: blob.size(), path, - name, + name: name.into_owned(), }, content, - }); + })); } else if let Ok(new_tree) = object.into_tree() { tree = new_tree; } else { - panic!("unknown item kind"); + anyhow::bail!("Given path not tree nor blob... what is it?!"); } } let mut tree_items = Vec::new(); for item in tree.iter() { - let object = item.to_object(&repo).unwrap(); - - let name = item.name().unwrap().to_string(); + let object = item + .to_object(&repo) + .context("Expected item in tree to be object but it wasn't")?; + + let name = String::from_utf8_lossy(item.name_bytes()).into_owned(); let path = path.clone().unwrap_or_default().join(&name); if let Some(blob) = object.as_blob() { @@ -145,14 +160,14 @@ } } - PathDestination::Tree(tree_items) + Ok(PathDestination::Tree(tree_items)) }) .await - .unwrap() + .context("Failed to join Tokio task")? } #[instrument(skip(self))] - pub async fn tag_info(self: Arc, tag_name: &str) -> DetailedTag { + pub async fn tag_info(self: Arc, tag_name: &str) -> Result { let reference = format!("refs/tags/{tag_name}"); let tag_name = tag_name.to_string(); @@ -161,10 +176,10 @@ let tag = repo .find_reference(&reference) - .unwrap() + .context("Given reference does not exist in repository")? .peel_to_tag() - .unwrap(); - let tag_target = tag.target().unwrap(); + .context("Couldn't get to a tag from the given reference")?; + let tag_target = tag.target().context("Couldn't find tagged object")?; let tagged_object = match tag_target.kind() { Some(ObjectType::Commit) => Some(TaggedObject::Commit(tag_target.id().to_string())), @@ -172,45 +187,49 @@ None | Some(_) => None, }; - DetailedTag { + Ok(DetailedTag { name: tag_name, - tagger: tag.tagger().map(Into::into), - message: tag.message().unwrap().to_string(), + tagger: tag.tagger().map(TryInto::try_into).transpose()?, + message: tag + .message_bytes() + .map(String::from_utf8_lossy) + .unwrap_or_else(|| Cow::Borrowed("")) + .into_owned(), tagged_object, - } + }) }) .await - .unwrap() + .context("Failed to join Tokio task")? } #[instrument(skip(self))] - pub async fn refs(self: Arc) -> Arc { + pub async fn refs(self: Arc) -> Result, Arc> { let git = self.git.clone(); git.refs - .get_with(self.cache_key.clone(), async move { + .try_get_with(self.cache_key.clone(), async move { tokio::task::spawn_blocking(move || { let repo = self.repo.lock(); - let ref_iter = repo.references().unwrap(); + let ref_iter = repo.references().context("Couldn't get list of references for repository")?; let mut built_refs = Refs::default(); for ref_ in ref_iter { - let ref_ = ref_.unwrap(); + let ref_ = ref_?; if ref_.is_branch() { - let commit = ref_.peel_to_commit().unwrap(); + let commit = ref_.peel_to_commit().context("Reference is apparently a branch but I couldn't get to the HEAD of it")?; built_refs.branch.push(Branch { - name: ref_.shorthand().unwrap().to_string(), - commit: commit.into(), + name: String::from_utf8_lossy(ref_.shorthand_bytes()).into_owned(), + commit: commit.try_into()?, }); } else if ref_.is_tag() { if let Ok(tag) = ref_.peel_to_tag() { built_refs.tag.push(Tag { - name: ref_.shorthand().unwrap().to_string(), - tagger: tag.tagger().map(Into::into), + name: String::from_utf8_lossy(ref_.shorthand_bytes()).into_owned(), + tagger: tag.tagger().map(TryInto::try_into).transpose()?, }); } } @@ -225,28 +244,34 @@ two_tagger.cmp(&one_tagger) }); - Arc::new(built_refs) + Ok(Arc::new(built_refs)) }) .await - .unwrap() + .context("Failed to join Tokio task")? }) .await } #[instrument(skip(self))] - pub async fn readme(self: Arc) -> Option<(ReadmeFormat, Arc)> { + pub async fn readme( + self: Arc, + ) -> Result)>, Arc> { const README_FILES: &[&str] = &["README.md", "README", "README.txt"]; let git = self.git.clone(); git.readme_cache - .get_with(self.cache_key.clone(), async move { + .try_get_with(self.cache_key.clone(), async move { tokio::task::spawn_blocking(move || { let repo = self.repo.lock(); - let head = repo.head().unwrap(); - let commit = head.peel_to_commit().unwrap(); - let tree = commit.tree().unwrap(); + let head = repo.head().context("Couldn't find HEAD of repository")?; + let commit = head.peel_to_commit().context( + "Couldn't find the commit that the HEAD of the repository refers to", + )?; + let tree = commit + .tree() + .context("Couldn't get the tree that the HEAD refers to")?; for name in README_FILES { let tree_entry = if let Some(file) = tree.get_name(name) { @@ -273,64 +298,68 @@ if Path::new(name).extension().and_then(OsStr::to_str) == Some("md") { let value = parse_and_transform_markdown(content, &self.git.syntax_set); - return Some((ReadmeFormat::Markdown, Arc::from(value))); + return Ok(Some((ReadmeFormat::Markdown, Arc::from(value)))); } - return Some((ReadmeFormat::Plaintext, Arc::from(content))); + return Ok(Some((ReadmeFormat::Plaintext, Arc::from(content)))); } - None + Ok(None) }) .await - .unwrap() + .context("Failed to join Tokio task")? }) .await } #[instrument(skip(self))] - pub async fn latest_commit(self: Arc) -> Commit { + pub async fn latest_commit(self: Arc) -> Result { tokio::task::spawn_blocking(move || { let repo = self.repo.lock(); - let head = repo.head().unwrap(); - let commit = head.peel_to_commit().unwrap(); + let head = repo.head().context("Couldn't find HEAD of repository")?; + let commit = head + .peel_to_commit() + .context("Couldn't find commit HEAD of repository refers to")?; let (diff_plain, diff_output, diff_stats) = - fetch_diff_and_stats(&repo, &commit, &self.git.syntax_set); + fetch_diff_and_stats(&repo, &commit, &self.git.syntax_set)?; - let mut commit = Commit::from(commit); + let mut commit = Commit::try_from(commit)?; commit.diff_stats = diff_stats; commit.diff = diff_output; commit.diff_plain = diff_plain; - commit + Ok(commit) }) .await - .unwrap() + .context("Failed to join Tokio task")? } #[instrument(skip(self))] - pub async fn commit(self: Arc, commit: &str) -> Arc { - let commit = Oid::from_str(commit).unwrap(); + pub async fn commit(self: Arc, commit: &str) -> Result, Arc> { + let commit = Oid::from_str(commit) + .map_err(anyhow::Error::from) + .map_err(Arc::new)?; let git = self.git.clone(); git.commits - .get_with(commit, async move { + .try_get_with(commit, async move { tokio::task::spawn_blocking(move || { let repo = self.repo.lock(); - let commit = repo.find_commit(commit).unwrap(); + let commit = repo.find_commit(commit)?; let (diff_plain, diff_output, diff_stats) = - fetch_diff_and_stats(&repo, &commit, &self.git.syntax_set); + fetch_diff_and_stats(&repo, &commit, &self.git.syntax_set)?; - let mut commit = Commit::from(commit); + let mut commit = Commit::try_from(commit)?; commit.diff_stats = diff_stats; commit.diff = diff_output; commit.diff_plain = diff_plain; - Arc::new(commit) + Ok(Arc::new(commit)) }) .await - .unwrap() + .context("Failed to join Tokio task")? }) .await } @@ -427,14 +456,16 @@ time: OffsetDateTime, } -impl From> for CommitUser { - fn from(v: Signature<'_>) -> Self { - CommitUser { - name: v.name().unwrap().to_string(), - email: v.email().unwrap().to_string(), +impl TryFrom> for CommitUser { + type Error = anyhow::Error; + + fn try_from(v: Signature<'_>) -> Result { + Ok(CommitUser { + name: String::from_utf8_lossy(v.name_bytes()).into_owned(), + email: String::from_utf8_lossy(v.email_bytes()).into_owned(), email_md5: format!("{:x}", md5::compute(v.email_bytes())), - time: OffsetDateTime::from_unix_timestamp(v.when().seconds()).unwrap(), - } + time: OffsetDateTime::from_unix_timestamp(v.when().seconds())?, + }) } } @@ -469,21 +500,31 @@ pub diff: String, pub diff_plain: Bytes, } + +impl TryFrom> for Commit { + type Error = anyhow::Error; -impl From> for Commit { - fn from(commit: git2::Commit<'_>) -> Self { - Commit { - author: commit.author().into(), - committer: commit.committer().into(), + fn try_from(commit: git2::Commit<'_>) -> Result { + Ok(Commit { + author: CommitUser::try_from(commit.author())?, + committer: CommitUser::try_from(commit.committer())?, oid: commit.id().to_string(), tree: commit.tree_id().to_string(), parents: commit.parent_ids().map(|v| v.to_string()).collect(), - summary: commit.summary().unwrap().to_string(), - body: commit.body().map(ToString::to_string).unwrap_or_default(), + summary: commit + .summary_bytes() + .map(String::from_utf8_lossy) + .unwrap_or_else(|| Cow::Borrowed("")) + .into_owned(), + body: commit + .body_bytes() + .map(String::from_utf8_lossy) + .unwrap_or_else(|| Cow::Borrowed("")) + .into_owned(), diff_stats: String::with_capacity(0), diff: String::with_capacity(0), diff_plain: Bytes::new(), - } + }) } } @@ -522,37 +563,35 @@ repo: &git2::Repository, commit: &git2::Commit<'_>, syntax_set: &SyntaxSet, -) -> (Bytes, String, String) { - let current_tree = commit.tree().unwrap(); +) -> Result<(Bytes, String, String)> { + let current_tree = commit.tree().context("Couldn't get tree for the commit")?; let parent_tree = commit.parents().next().and_then(|v| v.tree().ok()); let mut diff_opts = DiffOptions::new(); - let mut diff = repo - .diff_tree_to_tree( - parent_tree.as_ref(), - Some(¤t_tree), - Some(&mut diff_opts), - ) - .unwrap(); + let mut diff = repo.diff_tree_to_tree( + parent_tree.as_ref(), + Some(¤t_tree), + Some(&mut diff_opts), + )?; let mut diff_plain = BytesMut::new(); - let email = diff.format_email(1, 1, commit, None).unwrap(); + let email = diff + .format_email(1, 1, commit, None) + .context("Couldn't build diff for commit")?; diff_plain.extend_from_slice(&*email); let diff_stats = diff - .stats() - .unwrap() - .to_buf(DiffStatsFormat::FULL, 80) - .unwrap() + .stats()? + .to_buf(DiffStatsFormat::FULL, 80)? .as_str() - .unwrap() + .unwrap_or("") .to_string(); - let diff_output = format_diff(&diff, syntax_set); + let diff_output = format_diff(&diff, syntax_set)?; - (diff_plain.freeze(), diff_output, diff_stats) + Ok((diff_plain.freeze(), diff_output, diff_stats)) } -fn format_file(content: &[u8], extension: &str, syntax_set: &SyntaxSet) -> String { - let content = std::str::from_utf8(content).unwrap(); +fn format_file(content: &[u8], extension: &str, syntax_set: &SyntaxSet) -> Result { + let content = String::from_utf8_lossy(content); let syntax = syntax_set .find_syntax_by_extension(extension) @@ -560,20 +599,20 @@ let mut html_generator = ClassedHTMLGenerator::new_with_class_style(syntax, syntax_set, ClassStyle::Spaced); - for line in LinesWithEndings::from(content) { + for line in LinesWithEndings::from(&content) { html_generator .parse_html_for_line_which_includes_newline(line) - .unwrap(); + .context("Couldn't parse line of file")?; } - format!( + Ok(format!( "{}", html_generator.finalize().replace('\n', "\n") - ) + )) } #[instrument(skip(diff, syntax_set))] -fn format_diff(diff: &git2::Diff<'_>, syntax_set: &SyntaxSet) -> String { +fn format_diff(diff: &git2::Diff<'_>, syntax_set: &SyntaxSet) -> Result { let mut diff_output = String::new(); diff.print(DiffFormat::Patch, |delta, _diff_hunk, diff_line| { @@ -590,11 +629,14 @@ let line = String::from_utf8_lossy(diff_line.content()); let extension = if should_highlight_as_source { - let path = delta.new_file().path().unwrap(); - path.extension() - .or_else(|| path.file_name()) - .unwrap() - .to_string_lossy() + if let Some(path) = delta.new_file().path() { + path.extension() + .or_else(|| path.file_name()) + .map(|v| v.to_string_lossy()) + .unwrap_or_else(|| Cow::Borrowed("")) + } else { + Cow::Borrowed("") + } } else { Cow::Borrowed("patch") }; @@ -603,11 +645,9 @@ .unwrap_or_else(|| syntax_set.find_syntax_plain_text()); let mut html_generator = ClassedHTMLGenerator::new_with_class_style(syntax, syntax_set, ClassStyle::Spaced); - html_generator - .parse_html_for_line_which_includes_newline(&line) - .unwrap(); + let _ = html_generator.parse_html_for_line_which_includes_newline(&line); if let Some(class) = class { - write!(diff_output, r#""#).unwrap(); + let _ = write!(diff_output, r#""#); } diff_output.push_str(&html_generator.finalize()); if class.is_some() { @@ -616,7 +656,7 @@ true }) - .unwrap(); + .context("Failed to prepare diff")?; - diff_output + Ok(diff_output) } diff --git a/src/main.rs b/src/main.rs index 0d3b9c2..8d04be6 100644 --- a/src/main.rs +++ a/src/main.rs @@ -55,11 +55,20 @@ let theme = bat_assets.get_theme("GitHub"); let css = syntect::html::css_for_theme_with_class_style(theme, ClassStyle::Spaced).unwrap(); - let css = Box::leak(format!(r#"@media (prefers-color-scheme: light){{{}}}"#, css).into_boxed_str().into_boxed_bytes()); + let css = Box::leak( + format!(r#"@media (prefers-color-scheme: light){{{}}}"#, css) + .into_boxed_str() + .into_boxed_bytes(), + ); let dark_theme = bat_assets.get_theme("TwoDark"); - let dark_css = syntect::html::css_for_theme_with_class_style(dark_theme, ClassStyle::Spaced).unwrap(); - let dark_css = Box::leak(format!(r#"@media (prefers-color-scheme: dark){{{}}}"#, dark_css).into_boxed_str().into_boxed_bytes()); + let dark_css = + syntect::html::css_for_theme_with_class_style(dark_theme, ClassStyle::Spaced).unwrap(); + let dark_css = Box::leak( + format!(r#"@media (prefers-color-scheme: dark){{{}}}"#, dark_css) + .into_boxed_str() + .into_boxed_bytes(), + ); let app = Router::new() .route("/", get(methods::index::handle)) diff --git a/src/methods/repo.rs b/src/methods/repo.rs index 4be9dcd..9fe2ea4 100644 --- a/src/methods/repo.rs +++ a/src/methods/repo.rs @@ -8,6 +8,7 @@ }; use askama::Template; +use axum::http::StatusCode; use axum::{ body::HttpBody, extract::Query, @@ -53,6 +54,28 @@ } } +pub type Result = std::result::Result; + +pub struct Error(anyhow::Error); + +impl From> for Error { + fn from(e: Arc) -> Self { + Self(anyhow::Error::msg(format!("{:?}", e))) + } +} + +impl From for Error { + fn from(e: anyhow::Error) -> Self { + Self(e) + } +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + (StatusCode::INTERNAL_SERVER_ERROR, format!("{:?}", self.0)).into_response() + } +} + // this is some wicked, wicked abuse of axum right here... pub async fn service( mut request: Request, @@ -71,22 +94,28 @@ let mut child_path = None; + macro_rules! h { + ($handler:ident) => { + BoxCloneService::new($handler.into_service()) + }; + } + let mut service = match uri_parts.pop() { Some("about") => BoxCloneService::new(handle_about.into_service()), // TODO: https://man.archlinux.org/man/git-http-backend.1.en // TODO: GIT_PROTOCOL Some("refs") if uri_parts.last() == Some(&"info") => { uri_parts.pop(); - BoxCloneService::new(handle_info_refs.into_service()) + h!(handle_info_refs) } - Some("git-upload-pack") => BoxCloneService::new(handle_git_upload_pack.into_service()), - Some("refs") => BoxCloneService::new(handle_refs.into_service()), - Some("log") => BoxCloneService::new(handle_log.into_service()), - Some("tree") => BoxCloneService::new(handle_tree.into_service()), - Some("commit") => BoxCloneService::new(handle_commit.into_service()), - Some("diff") => BoxCloneService::new(handle_diff.into_service()), - Some("patch") => BoxCloneService::new(handle_patch.into_service()), - Some("tag") => BoxCloneService::new(handle_tag.into_service()), + Some("git-upload-pack") => h!(handle_git_upload_pack), + Some("refs") => h!(handle_refs), + Some("log") => h!(handle_log), + Some("tree") => h!(handle_tree), + Some("commit") => h!(handle_commit), + Some("diff") => h!(handle_diff), + Some("patch") => h!(handle_patch), + Some("tag") => h!(handle_tag), Some(v) => { uri_parts.push(v); @@ -107,9 +136,9 @@ child_path = Some(reconstructed_path.into_iter().collect::().clean()); - BoxCloneService::new(handle_tree.into_service()) + h!(handle_tree) } else { - BoxCloneService::new(handle_summary.into_service()) + h!(handle_summary) } } None => panic!("not found"), @@ -142,20 +171,20 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Extension(db): Extension, -) -> Response { - let open_repo = git.repo(repository_path).await; - let refs = open_repo.refs().await; +) -> Result { + 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 commits = commit_tree.fetch_latest(11, 0).await; let commit_list = commits.iter().map(Yoke::get).collect(); - into_response(&SummaryView { + Ok(into_response(&SummaryView { repo, refs, commit_list, - }) + })) } #[derive(Deserialize)] @@ -176,11 +205,11 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Response { - let open_repo = git.repo(repository_path).await; - let tag = open_repo.tag_info(&query.name).await; +) -> Result { + let open_repo = git.repo(repository_path).await?; + let tag = open_repo.tag_info(&query.name).await?; - into_response(&TagView { repo, tag }) + Ok(into_response(&TagView { repo, tag })) } #[derive(Deserialize)] @@ -204,7 +233,7 @@ Extension(repo): Extension, Extension(db): Extension, Query(query): Query, -) -> Response { +) -> Result { let offset = query.offset.unwrap_or(0); let reference = format!("refs/heads/{}", query.branch.as_deref().unwrap_or("master")); @@ -221,12 +250,12 @@ let commits = commits.iter().map(Yoke::get).collect(); - into_response(&LogView { + Ok(into_response(&LogView { repo, commits, next_offset, branch: query.branch, - }) + })) } #[derive(Deserialize)] @@ -237,7 +266,7 @@ pub async fn handle_info_refs( Extension(RepositoryPath(repository_path)): Extension, Query(query): Query, -) -> Response { +) -> Result { // todo: tokio command let out = std::process::Command::new("git") .arg("http-backend") @@ -248,13 +277,13 @@ .output() .unwrap(); - crate::git_cgi::cgi_to_response(&out.stdout) + Ok(crate::git_cgi::cgi_to_response(&out.stdout)) } pub async fn handle_git_upload_pack( Extension(RepositoryPath(repository_path)): Extension, body: Bytes, -) -> Response { +) -> Result { // todo: tokio command let mut child = std::process::Command::new("git") .arg("http-backend") @@ -270,7 +299,7 @@ child.stdin.as_mut().unwrap().write_all(&body).unwrap(); let out = child.wait_with_output().unwrap(); - crate::git_cgi::cgi_to_response(&out.stdout) + Ok(crate::git_cgi::cgi_to_response(&out.stdout)) } #[derive(Template)] @@ -284,11 +313,11 @@ Extension(repo): Extension, Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, -) -> Response { - let open_repo = git.repo(repository_path).await; - let refs = open_repo.refs().await; +) -> Result { + let open_repo = git.repo(repository_path).await?; + let refs = open_repo.refs().await?; - into_response(&RefsView { repo, refs }) + Ok(into_response(&RefsView { repo, refs })) } #[derive(Template)] @@ -302,11 +331,11 @@ Extension(repo): Extension, Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, -) -> Response { - let open_repo = git.clone().repo(repository_path).await; - let readme = open_repo.readme().await; +) -> Result { + let open_repo = git.clone().repo(repository_path).await?; + let readme = open_repo.readme().await?; - into_response(&AboutView { repo, readme }) + Ok(into_response(&AboutView { repo, readme })) } #[derive(Template)] @@ -326,15 +355,15 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Response { - let open_repo = git.repo(repository_path).await; +) -> Result { + let open_repo = git.repo(repository_path).await?; let commit = if let Some(commit) = query.id { - open_repo.commit(&commit).await + open_repo.commit(&commit).await? } else { - Arc::new(open_repo.latest_commit().await) + Arc::new(open_repo.latest_commit().await?) }; - into_response(&CommitView { repo, commit }) + Ok(into_response(&CommitView { repo, commit })) } #[derive(Deserialize)] @@ -367,7 +396,7 @@ Extension(ChildPath(child_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Response { +) -> Result { #[derive(Template)] #[template(path = "repo/tree.html")] pub struct TreeView { @@ -383,15 +412,17 @@ pub file: FileWithContent, } - let open_repo = git.repo(repository_path).await; + let open_repo = git.repo(repository_path).await?; - match open_repo - .path(child_path, query.id.as_deref(), query.branch.clone()) - .await - { - PathDestination::Tree(items) => into_response(&TreeView { repo, items, query }), - PathDestination::File(file) => into_response(&FileView { repo, file }), - } + Ok( + match open_repo + .path(child_path, query.id.as_deref(), query.branch.clone()) + .await? + { + PathDestination::Tree(items) => into_response(&TreeView { repo, items, query }), + PathDestination::File(file) => into_response(&FileView { repo, file }), + }, + ) } #[derive(Template)] @@ -406,27 +437,27 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Response { - let open_repo = git.repo(repository_path).await; +) -> Result { + let open_repo = git.repo(repository_path).await?; let commit = if let Some(commit) = query.id { - open_repo.commit(&commit).await + open_repo.commit(&commit).await? } else { - Arc::new(open_repo.latest_commit().await) + Arc::new(open_repo.latest_commit().await?) }; - into_response(&DiffView { repo, commit }) + Ok(into_response(&DiffView { repo, commit })) } pub async fn handle_patch( Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Response { - let open_repo = git.repo(repository_path).await; +) -> Result { + let open_repo = git.repo(repository_path).await?; let commit = if let Some(commit) = query.id { - open_repo.commit(&commit).await + open_repo.commit(&commit).await? } else { - Arc::new(open_repo.latest_commit().await) + Arc::new(open_repo.latest_commit().await?) }; let headers = [( @@ -434,5 +465,5 @@ HeaderValue::from_static("text/plain"), )]; - (headers, commit.diff_plain.clone()).into_response() + Ok((headers, commit.diff_plain.clone()).into_response()) } -- rgit 0.1.3