Skip to content

Commit

Permalink
Retain references across pages
Browse files Browse the repository at this point in the history
  • Loading branch information
w4 committed Dec 31, 2023
1 parent 3334145 commit 39bdc18
Show file tree
Hide file tree
Showing 20 changed files with 153 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ moka = { version = "0.12.0", features = ["future"] }
once_cell = "1.18"
path-clean = "1.0.1"
parking_lot = "0.12"
serde = { version = "1.0", features = ["derive"] }
serde = { version = "1.0", features = ["derive", "rc"] }
sha2 = "0.10"
syntect = "5"
sled = { version = "0.34", features = ["compression"] }
Expand Down
11 changes: 8 additions & 3 deletions src/database/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{
use git2::Sort;
use ini::Ini;
use time::OffsetDateTime;
use tracing::{info, info_span};
use tracing::{error, info, info_span};

use crate::database::schema::{
commit::Commit,
Expand Down Expand Up @@ -89,7 +89,9 @@ fn update_repository_reflog(scan_path: &Path, db: &sled::Db) {
let reference = reference.unwrap();

let reference_name = String::from_utf8_lossy(reference.name_bytes());
if !reference_name.starts_with("refs/heads/") {
if !reference_name.starts_with("refs/heads/")
&& !reference_name.starts_with("refs/tags/")
{
continue;
}

Expand Down Expand Up @@ -119,7 +121,10 @@ fn update_repository_reflog(scan_path: &Path, db: &sled::Db) {
// TODO: only scan revs from the last time we looked
let mut revwalk = git_repository.revwalk().unwrap();
revwalk.set_sorting(Sort::REVERSE).unwrap();
revwalk.push_ref(&reference_name).unwrap();
if let Err(error) = revwalk.push_ref(&reference_name) {
error!(%error, "Failed to revwalk reference");
continue;
}

let mut i = 0;
for rev in revwalk {
Expand Down
48 changes: 30 additions & 18 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use anyhow::{Context, Result};
use bytes::{Bytes, BytesMut};
use comrak::{ComrakOptions, ComrakPlugins};
use git2::{
BranchType, DiffFormat, DiffLineType, DiffOptions, DiffStatsFormat, Email, EmailCreateOptions,
ObjectType, Oid, Signature,
DiffFormat, DiffLineType, DiffOptions, DiffStatsFormat, Email, EmailCreateOptions, ObjectType,
Oid, Signature,
};
use moka::future::Cache;
use parking_lot::Mutex;
Expand Down Expand Up @@ -51,7 +51,11 @@ impl Git {

impl Git {
#[instrument(skip(self))]
pub async fn repo(self: Arc<Self>, repo_path: PathBuf) -> Result<Arc<OpenRepository>> {
pub async fn repo(
self: Arc<Self>,
repo_path: PathBuf,
branch: Option<Arc<str>>,
) -> Result<Arc<OpenRepository>> {
let repo = tokio::task::spawn_blocking({
let repo_path = repo_path.clone();
move || git2::Repository::open(repo_path)
Expand All @@ -64,6 +68,7 @@ impl Git {
git: self,
cache_key: repo_path,
repo: Mutex::new(repo),
branch,
}))
}
}
Expand All @@ -72,14 +77,14 @@ pub struct OpenRepository {
git: Arc<Git>,
cache_key: PathBuf,
repo: Mutex<git2::Repository>,
branch: Option<Arc<str>>,
}

impl OpenRepository {
pub async fn path(
self: Arc<Self>,
path: Option<PathBuf>,
tree_id: Option<&str>,
branch: Option<String>,
formatted: bool,
) -> Result<PathDestination> {
let tree_id = tree_id
Expand All @@ -93,12 +98,11 @@ impl OpenRepository {
let mut tree = if let Some(tree_id) = tree_id {
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)?;
branch
.get()
} else if let Some(branch) = &self.branch {
let reference = repo.resolve_reference_from_short_name(branch)?;
reference
.peel_to_tree()
.context("Couldn't find tree for branch")?
.context("Couldn't find tree for reference")?
} else {
let head = repo.head()?;
head.peel_to_tree()
Expand Down Expand Up @@ -175,16 +179,14 @@ impl OpenRepository {
}

#[instrument(skip(self))]
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();

pub async fn tag_info(self: Arc<Self>) -> Result<DetailedTag> {
tokio::task::spawn_blocking(move || {
let tag_name = self.branch.clone().context("no tag given")?;
let repo = self.repo.lock();

let tag = repo
.find_reference(&reference)
.context("Given reference does not exist in repository")?
.find_reference(&format!("refs/tags/{tag_name}"))
.context("Given tag does not exist in repository")?
.peel_to_tag()
.context("Couldn't get to a tag from the given reference")?;
let tag_target = tag.target().context("Couldn't find tagged object")?;
Expand Down Expand Up @@ -222,7 +224,12 @@ impl OpenRepository {
tokio::task::spawn_blocking(move || {
let repo = self.repo.lock();

let head = repo.head().context("Couldn't find HEAD of repository")?;
let head = if let Some(reference) = &self.branch {
repo.resolve_reference_from_short_name(reference)?
} else {
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",
)?;
Expand Down Expand Up @@ -268,7 +275,12 @@ impl OpenRepository {
tokio::task::spawn_blocking(move || {
let repo = self.repo.lock();

let head = repo.head().context("Couldn't find HEAD of repository")?;
let head = if let Some(reference) = &self.branch {
repo.resolve_reference_from_short_name(reference)?
} else {
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")?;
Expand Down Expand Up @@ -381,7 +393,7 @@ pub enum TaggedObject {

#[derive(Debug)]
pub struct DetailedTag {
pub name: String,
pub name: Arc<str>,
pub tagger: Option<CommitUser>,
pub message: String,
pub tagged_object: Option<TaggedObject>,
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ use axum::{
use bat::assets::HighlightingAssets;
use clap::Parser;
use once_cell::sync::{Lazy, OnceCell};
use sha2::digest::FixedOutput;
use sha2::Digest;
use sha2::{digest::FixedOutput, Digest};
use sled::Db;
use syntect::html::ClassStyle;
use tokio::{
Expand Down
22 changes: 19 additions & 3 deletions src/methods/repo/about.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::sync::Arc;

use askama::Template;
use axum::{response::Response, Extension};
use axum::{extract::Query, response::Response, Extension};
use serde::Deserialize;

use crate::{
git::ReadmeFormat,
Expand All @@ -10,20 +11,35 @@ use crate::{
Git,
};

#[derive(Deserialize)]
pub struct UriQuery {
#[serde(rename = "h")]
pub branch: Option<Arc<str>>,
}

#[derive(Template)]
#[template(path = "repo/about.html")]
pub struct View {
repo: Repository,
readme: Option<(ReadmeFormat, Arc<str>)>,
branch: Option<Arc<str>>,
}

pub async fn handle(
Extension(repo): Extension<Repository>,
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
) -> Result<Response> {
let open_repo = git.clone().repo(repository_path).await?;
let open_repo = git
.clone()
.repo(repository_path, query.branch.clone())
.await?;
let readme = open_repo.readme().await?;

Ok(into_response(&View { repo, readme }))
Ok(into_response(&View {
repo,
readme,
branch: query.branch,
}))
}
11 changes: 9 additions & 2 deletions src/methods/repo/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ use crate::{
pub struct View {
pub repo: Repository,
pub commit: Arc<Commit>,
pub branch: Option<Arc<str>>,
}

#[derive(Deserialize)]
pub struct UriQuery {
pub id: Option<String>,
#[serde(rename = "h")]
pub branch: Option<Arc<str>>,
}

pub async fn handle(
Expand All @@ -29,12 +32,16 @@ pub async fn handle(
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
) -> Result<Response> {
let open_repo = git.repo(repository_path).await?;
let open_repo = git.repo(repository_path, query.branch.clone()).await?;
let commit = if let Some(commit) = query.id {
open_repo.commit(&commit).await?
} else {
Arc::new(open_repo.latest_commit().await?)
};

Ok(into_response(&View { repo, commit }))
Ok(into_response(&View {
repo,
commit,
branch: query.branch,
}))
}
11 changes: 8 additions & 3 deletions src/methods/repo/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
pub struct View {
pub repo: Repository,
pub commit: Arc<Commit>,
pub branch: Option<Arc<str>>,
}

pub async fn handle(
Expand All @@ -28,22 +29,26 @@ pub async fn handle(
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
) -> Result<Response> {
let open_repo = git.repo(repository_path).await?;
let open_repo = git.repo(repository_path, query.branch.clone()).await?;
let commit = if let Some(commit) = query.id {
open_repo.commit(&commit).await?
} else {
Arc::new(open_repo.latest_commit().await?)
};

Ok(into_response(&View { repo, commit }))
Ok(into_response(&View {
repo,
commit,
branch: query.branch,
}))
}

pub async fn handle_plain(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
) -> Result<Response> {
let open_repo = git.repo(repository_path).await?;
let open_repo = git.repo(repository_path, query.branch).await?;
let commit = if let Some(commit) = query.id {
open_repo.commit(&commit).await?
} else {
Expand Down
19 changes: 15 additions & 4 deletions src/methods/repo/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,22 @@ pub async fn get_branch_commits(
amount: usize,
offset: usize,
) -> Result<Vec<YokedCommit>> {
let reference = branch.map(|branch| format!("refs/heads/{branch}"));
if let Some(reference) = branch {
let commit_tree = repository
.get()
.commit_tree(database, &format!("refs/heads/{reference}"))?;
let commit_tree = commit_tree.fetch_latest(amount, offset).await;

if let Some(reference) = reference {
let commit_tree = repository.get().commit_tree(database, &reference)?;
return Ok(commit_tree.fetch_latest(amount, offset).await);
if !commit_tree.is_empty() {
return Ok(commit_tree);
}

let tag_tree = repository
.get()
.commit_tree(database, &format!("refs/tags/{reference}"))?;
let tag_tree = tag_tree.fetch_latest(amount, offset).await;

return Ok(tag_tree);
}

for branch in DEFAULT_BRANCHES {
Expand Down
4 changes: 3 additions & 1 deletion src/methods/repo/refs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, sync::Arc};

use anyhow::Context;
use askama::Template;
Expand All @@ -17,6 +17,7 @@ use crate::{
pub struct View {
repo: Repository,
refs: Refs,
branch: Option<Arc<str>>,
}

#[allow(clippy::unused_async)]
Expand Down Expand Up @@ -46,5 +47,6 @@ pub async fn handle(
Ok(into_response(&View {
repo,
refs: Refs { heads, tags },
branch: None,
}))
}
6 changes: 4 additions & 2 deletions src/methods/repo/smart_git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ use httparse::Status;
use tokio_util::io::StreamReader;
use tracing::warn;

use crate::methods::repo::{Repository, RepositoryPath, Result};
use crate::StatusCode;
use crate::{
methods::repo::{Repository, RepositoryPath, Result},
StatusCode,
};

#[allow(clippy::unused_async)]
pub async fn handle(
Expand Down
4 changes: 3 additions & 1 deletion src/methods/repo/summary.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, sync::Arc};

use anyhow::Context;
use askama::Template;
Expand All @@ -20,6 +20,7 @@ pub struct View<'a> {
repo: Repository,
refs: Refs,
commit_list: Vec<&'a crate::database::schema::commit::Commit<'a>>,
branch: Option<Arc<str>>,
}

pub async fn handle(
Expand Down Expand Up @@ -51,6 +52,7 @@ pub async fn handle(
repo,
refs: Refs { heads, tags },
commit_list,
branch: None,
}))
}

Expand Down
Loading

0 comments on commit 39bdc18

Please sign in to comment.