gitscope
← rgit / 0.1.4 / src/methods/repo/log.rs
https://dev.kronoz.win/r/rgit.git
src/methods/repo/log.rs · Rust
Blame Raw
  1use std::sync::Arc;
  2
  3use anyhow::Context;
  4use askama::Template;
  5use axum::{extract::Query, response::IntoResponse, Extension};
  6use serde::Deserialize;
  7
  8use crate::{
  9    database::schema::{commit::YokedCommit, repository::YokedRepository},
 10    into_response,
 11    methods::{
 12        filters,
 13        repo::{Repository, Result, DEFAULT_BRANCHES},
 14    },
 15};
 16
 17#[derive(Deserialize)]
 18pub struct UriQuery {
 19    #[serde(rename = "ofs")]
 20    offset: Option<u64>,
 21    #[serde(rename = "h")]
 22    branch: Option<String>,
 23}
 24
 25#[derive(Template)]
 26#[template(path = "repo/log.html")]
 27pub struct View {
 28    repo: Repository,
 29    commits: Vec<YokedCommit>,
 30    next_offset: Option<u64>,
 31    branch: Option<String>,
 32}
 33
 34pub async fn handle(
 35    Extension(repo): Extension<Repository>,
 36    Extension(db): Extension<Arc<rocksdb::DB>>,
 37    Query(query): Query<UriQuery>,
 38) -> Result<impl IntoResponse> {
 39    tokio::task::spawn_blocking(move || {
 40        let offset = query.offset.unwrap_or(0);
 41
 42        let repository = crate::database::schema::repository::Repository::open(&db, &*repo)?
 43            .context("Repository does not exist")?;
 44        let mut commits =
 45            get_branch_commits(&repository, &db, query.branch.as_deref(), 101, offset)?;
 46
 47        let next_offset = if commits.len() == 101 {
 48            commits.pop();
 49            Some(offset + 100)
 50        } else {
 51            None
 52        };
 53
 54        Ok(into_response(View {
 55            repo,
 56            commits,
 57            next_offset,
 58            branch: query.branch,
 59        }))
 60    })
 61    .await
 62    .context("Failed to attach to tokio task")?
 63}
 64
 65pub fn get_branch_commits(
 66    repository: &YokedRepository,
 67    database: &Arc<rocksdb::DB>,
 68    branch: Option<&str>,
 69    amount: u64,
 70    offset: u64,
 71) -> Result<Vec<YokedCommit>> {
 72    if let Some(reference) = branch {
 73        let commit_tree = repository
 74            .get()
 75            .commit_tree(database.clone(), &format!("refs/heads/{reference}"));
 76        let commit_tree = commit_tree.fetch_latest(amount, offset)?;
 77
 78        if !commit_tree.is_empty() {
 79            return Ok(commit_tree);
 80        }
 81
 82        let tag_tree = repository
 83            .get()
 84            .commit_tree(database.clone(), &format!("refs/tags/{reference}"));
 85        let tag_tree = tag_tree.fetch_latest(amount, offset)?;
 86
 87        return Ok(tag_tree);
 88    }
 89
 90    for branch in repository
 91        .get()
 92        .default_branch
 93        .as_deref()
 94        .into_iter()
 95        .chain(DEFAULT_BRANCHES.into_iter())
 96    {
 97        let commit_tree = repository.get().commit_tree(database.clone(), branch);
 98        let commits = commit_tree.fetch_latest(amount, offset)?;
 99
100        if !commits.is_empty() {
101            return Ok(commits);
102        }
103    }
104
105    Ok(vec![])
106}