diff --git a/Cargo.lock b/Cargo.lock
@@ -199,6 +199,18 @@ dependencies = [
"mime",
]
+[[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"
@@ -949,6 +961,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"
version = "0.1.19"
@@ -1918,6 +1936,7 @@ dependencies = [
"anyhow",
"askama",
"axum",
+ "axum-macros",
"bat",
"bincode",
"bytes",
diff --git a/Cargo.toml b/Cargo.toml
@@ -7,7 +7,9 @@ edition = "2021"
[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
@@ -3,6 +3,7 @@ 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 {
impl Git {
#[instrument(skip(self))]
- pub async fn repo(self: Arc<Self>, repo_path: PathBuf) -> Arc<OpenRepository> {
+ pub async fn repo(self: Arc<Self>, repo_path: PathBuf) -> Result<Arc<OpenRepository>> {
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 @@ impl OpenRepository {
path: Option<PathBuf>,
tree_id: Option<&str>,
branch: Option<String>,
- ) -> PathDestination {
- let tree_id = tree_id.map(Oid::from_str).transpose().unwrap();
+ ) -> Result<PathDestination> {
+ 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);
+ .map(|v| v.to_string_lossy())
+ .unwrap_or_else(|| Cow::Borrowed(""));
+ let content = format_file(blob.content(), &extension, &self.git.syntax_set)?;
- return PathDestination::File(FileWithContent {
+ 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 object = item
+ .to_object(&repo)
+ .context("Expected item in tree to be object but it wasn't")?;
- let name = item.name().unwrap().to_string();
+ 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 @@ impl OpenRepository {
}
}
- 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<Self>, tag_name: &str) -> DetailedTag {
+ pub async fn tag_info(self: Arc<Self>, tag_name: &str) -> Result<DetailedTag> {
let reference = format!("refs/tags/{tag_name}");
let tag_name = tag_name.to_string();
@@ -161,10 +176,10 @@ impl OpenRepository {
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 @@ impl OpenRepository {
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<Self>) -> Arc<Refs> {
+ pub async fn refs(self: Arc<Self>) -> Result<Arc<Refs>, Arc<anyhow::Error>> {
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 @@ impl OpenRepository {
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<Self>) -> Option<(ReadmeFormat, Arc<str>)> {
+ pub async fn readme(
+ self: Arc<Self>,
+ ) -> Result<Option<(ReadmeFormat, Arc<str>)>, Arc<anyhow::Error>> {
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 @@ impl OpenRepository {
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<Self>) -> Commit {
+ pub async fn latest_commit(self: Arc<Self>) -> Result<Commit> {
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<Self>, commit: &str) -> Arc<Commit> {
- let commit = Oid::from_str(commit).unwrap();
+ pub async fn commit(self: Arc<Self>, commit: &str) -> Result<Arc<Commit>, Arc<anyhow::Error>> {
+ 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 @@ pub struct CommitUser {
time: OffsetDateTime,
}
-impl From<Signature<'_>> for CommitUser {
- fn from(v: Signature<'_>) -> Self {
- CommitUser {
- name: v.name().unwrap().to_string(),
- email: v.email().unwrap().to_string(),
+impl TryFrom<Signature<'_>> for CommitUser {
+ type Error = anyhow::Error;
+
+ fn try_from(v: Signature<'_>) -> Result<Self> {
+ 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())?,
+ })
}
}
@@ -470,20 +501,30 @@ pub struct Commit {
pub diff_plain: Bytes,
}
-impl From<git2::Commit<'_>> for Commit {
- fn from(commit: git2::Commit<'_>) -> Self {
- Commit {
- author: commit.author().into(),
- committer: commit.committer().into(),
+impl TryFrom<git2::Commit<'_>> for Commit {
+ type Error = anyhow::Error;
+
+ fn try_from(commit: git2::Commit<'_>) -> Result<Self> {
+ 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 @@ fn fetch_diff_and_stats(
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<String> {
+ let content = String::from_utf8_lossy(content);
let syntax = syntax_set
.find_syntax_by_extension(extension)
@@ -560,20 +599,20 @@ fn format_file(content: &[u8], extension: &str, syntax_set: &SyntaxSet) -> Strin
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!(
"<code>{}</code>",
html_generator.finalize().replace('\n', "</code>\n<code>")
- )
+ ))
}
#[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<String> {
let mut diff_output = String::new();
diff.print(DiffFormat::Patch, |delta, _diff_hunk, diff_line| {
@@ -590,11 +629,14 @@ fn format_diff(diff: &git2::Diff<'_>, syntax_set: &SyntaxSet) -> String {
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 @@ fn format_diff(diff: &git2::Diff<'_>, syntax_set: &SyntaxSet) -> String {
.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#"<span class="diff-{class}">"#).unwrap();
+ let _ = write!(diff_output, r#"<span class="diff-{class}">"#);
}
diff_output.push_str(&html_generator.finalize());
if class.is_some() {
@@ -616,7 +656,7 @@ fn format_diff(diff: &git2::Diff<'_>, syntax_set: &SyntaxSet) -> String {
true
})
- .unwrap();
+ .context("Failed to prepare diff")?;
- diff_output
+ Ok(diff_output)
}
diff --git a/src/main.rs b/src/main.rs
@@ -55,11 +55,20 @@ async fn main() {
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
@@ -8,6 +8,7 @@ use std::{
};
use askama::Template;
+use axum::http::StatusCode;
use axum::{
body::HttpBody,
extract::Query,
@@ -53,6 +54,28 @@ impl Deref for RepositoryPath {
}
}
+pub type Result<T> = std::result::Result<T, Error>;
+
+pub struct Error(anyhow::Error);
+
+impl From<Arc<anyhow::Error>> for Error {
+ fn from(e: Arc<anyhow::Error>) -> Self {
+ Self(anyhow::Error::msg(format!("{:?}", e)))
+ }
+}
+
+impl From<anyhow::Error> 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<ReqBody: HttpBody + Send + Debug + 'static>(
mut request: Request<ReqBody>,
@@ -71,22 +94,28 @@ where
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 @@ where
child_path = Some(reconstructed_path.into_iter().collect::<PathBuf>().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 @@ pub async fn handle_summary(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Extension(db): Extension<sled::Db>,
-) -> Response {
- let open_repo = git.repo(repository_path).await;
- let refs = open_repo.refs().await;
+) -> Result<Response> {
+ 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 @@ pub async fn handle_tag(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<TagQuery>,
-) -> Response {
- let open_repo = git.repo(repository_path).await;
- let tag = open_repo.tag_info(&query.name).await;
+) -> Result<Response> {
+ 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 @@ pub async fn handle_log(
Extension(repo): Extension<Repository>,
Extension(db): Extension<sled::Db>,
Query(query): Query<LogQuery>,
-) -> Response {
+) -> Result<Response> {
let offset = query.offset.unwrap_or(0);
let reference = format!("refs/heads/{}", query.branch.as_deref().unwrap_or("master"));
@@ -221,12 +250,12 @@ pub async fn handle_log(
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 struct SmartGitQuery {
pub async fn handle_info_refs(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Query(query): Query<SmartGitQuery>,
-) -> Response {
+) -> Result<Response> {
// todo: tokio command
let out = std::process::Command::new("git")
.arg("http-backend")
@@ -248,13 +277,13 @@ pub async fn handle_info_refs(
.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<RepositoryPath>,
body: Bytes,
-) -> Response {
+) -> Result<Response> {
// todo: tokio command
let mut child = std::process::Command::new("git")
.arg("http-backend")
@@ -270,7 +299,7 @@ pub async fn handle_git_upload_pack(
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 @@ pub async fn handle_refs(
Extension(repo): Extension<Repository>,
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
-) -> Response {
- let open_repo = git.repo(repository_path).await;
- let refs = open_repo.refs().await;
+) -> Result<Response> {
+ 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 @@ pub async fn handle_about(
Extension(repo): Extension<Repository>,
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
-) -> Response {
- let open_repo = git.clone().repo(repository_path).await;
- let readme = open_repo.readme().await;
+) -> Result<Response> {
+ 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 @@ pub async fn handle_commit(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<CommitQuery>,
-) -> Response {
- let open_repo = git.repo(repository_path).await;
+) -> Result<Response> {
+ 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 @@ pub async fn handle_tree(
Extension(ChildPath(child_path)): Extension<ChildPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<TreeQuery>,
-) -> Response {
+) -> Result<Response> {
#[derive(Template)]
#[template(path = "repo/tree.html")]
pub struct TreeView {
@@ -383,15 +412,17 @@ pub async fn handle_tree(
pub file: FileWithContent,
}
- 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 }),
- }
+ let open_repo = git.repo(repository_path).await?;
+
+ 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 @@ pub async fn handle_diff(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<CommitQuery>,
-) -> Response {
- let open_repo = git.repo(repository_path).await;
+) -> Result<Response> {
+ 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<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<CommitQuery>,
-) -> Response {
- let open_repo = git.repo(repository_path).await;
+) -> Result<Response> {
+ 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 @@ pub async fn handle_patch(
HeaderValue::from_static("text/plain"),
)];
- (headers, commit.diff_plain.clone()).into_response()
+ Ok((headers, commit.diff_plain.clone()).into_response())
}