🏡 index : ~doyle/rgit.git

author Jordan Doyle <jordan@doyle.la> 2024-11-13 2:16:15.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-11-13 2:16:15.0 +00:00:00
commit
6595e8c4a50c9b8bab72aed3ad355538a5e92a63 [patch]
tree
000c03c41e62d869f85fe62a533fd30d87295394
parent
3430b7c5d480f182d26ccb6142d889534521306c
download
6595e8c4a50c9b8bab72aed3ad355538a5e92a63.tar.gz

Remove intermediary vecs/btreemaps for ordering on index



Diff

 Cargo.lock           |  2 +-
 templates/index.html | 16 +++++++++-------
 src/methods/index.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++-------------
 3 files changed, 48 insertions(+), 27 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8427b33..27dbd71 100644
--- a/Cargo.lock
+++ a/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
version = 3

[[package]]
name = "addr2line"
diff --git a/templates/index.html b/templates/index.html
index e9762a6..2abf597 100644
--- a/templates/index.html
+++ a/templates/index.html
@@ -13,21 +13,21 @@
        </thead>

        <tbody>
        {%- for (path, repositories) in repositories %}
            {%- if let Some(path) = path %}
        {%- for (path, repositories) in self.take_iter() %}
            {%- if !path.is_empty() %}
            <tr><td class="repo-section" colspan="4">{{ path }}</td></tr>
            {%- endif -%}

            {%- for repository in repositories %}
            {% set repository = repository.get() %}
            <tr class="{% if path.is_some() %}has-parent{% endif %}">
            {% set repository = repository.1.get() %}
            <tr class="{% if !path.is_empty() %}has-parent{% endif %}">
                <td>
                    <a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
                    <a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
                        {{- repository.name -}}
                    </a>
                </td>
                <td>
                    <a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
                    <a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
                        {%- if let Some(description) = repository.description.as_ref() -%}
                            {{- description -}}
                        {%- else -%}
@@ -36,14 +36,14 @@
                    </a>
                </td>
                <td>
                    <a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
                    <a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
                        {%- if let Some(owner) = repository.owner.as_ref() -%}
                            {{- owner -}}
                        {%- endif -%}
                    </a>
                </td>
                <td>
                    <a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
                    <a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
                        <time datetime="{{ repository.last_modified|format_time }}" title="{{ repository.last_modified|format_time }}">
                            {{- repository.last_modified|timeago -}}
                        </time>
diff --git a/src/methods/index.rs b/src/methods/index.rs
index 2bd3ac8..592001f 100644
--- a/src/methods/index.rs
+++ a/src/methods/index.rs
@@ -1,8 +1,12 @@
use std::{collections::BTreeMap, sync::Arc};
use std::{cell::RefCell, sync::Arc};

use anyhow::Context;
use askama::Template;
use axum::{response::IntoResponse, Extension};
use axum::{
    response::{IntoResponse, Response},
    Extension,
};
use itertools::{Either, Itertools};

use super::filters;
use crate::{
@@ -12,28 +16,45 @@

#[derive(Template)]
#[template(path = "index.html")]
pub struct View {
    pub repositories: BTreeMap<Option<String>, Vec<YokedRepository>>,
pub struct View<
    'a,
    Group: Iterator<Item = (&'a String, &'a YokedRepository)>,
    GroupIter: Iterator<Item = (&'a str, Group)>,
> {
    // this type sig is a necessary evil unfortunately, because askama takes a reference
    // to the data for rendering.
    pub repositories: RefCell<Either<GroupIter, std::iter::Empty<(&'a str, Group)>>>,
}

impl<'a, Group, GroupIter> View<'a, Group, GroupIter>
where
    Group: Iterator<Item = (&'a String, &'a YokedRepository)>,
    GroupIter: Iterator<Item = (&'a str, Group)>,
{
    fn take_iter(&self) -> Either<GroupIter, std::iter::Empty<(&'a str, Group)>> {
        self.repositories.replace(Either::Right(std::iter::empty()))
    }
}

pub async fn handle(
    Extension(db): Extension<Arc<rocksdb::DB>>,
) -> Result<impl IntoResponse, super::repo::Error> {
    let mut repositories: BTreeMap<Option<String>, Vec<YokedRepository>> = BTreeMap::new();

) -> Result<Response, super::repo::Error> {
    let fetched = tokio::task::spawn_blocking(move || Repository::fetch_all(&db))
        .await
        .context("Failed to join Tokio task")??;

    for (k, v) in fetched {
        // TODO: fixme
        let mut split: Vec<_> = k.split('/').collect();
        split.pop();
        let key = Some(split.join("/")).filter(|v| !v.is_empty());

        let k = repositories.entry(key).or_default();
        k.push(v);
    }

    Ok(into_response(View { repositories }))
    // rocksdb returned the keys already ordered for us so group_by is a nice
    // operation we can use here to avoid writing into a map to group. though,
    // now that i think about it it might act a little bit strangely when mixing
    // root repositories and nested repositories. we're going to have to prefix
    // root repositories with a null byte or something. i'll just leave this here
    // as a TODO.
    let repositories = fetched
        .iter()
        .group_by(|(k, _)| memchr::memrchr(b'/', k.as_bytes()).map_or("", |idx| &k[..idx]));

    Ok(into_response(View {
        repositories: Either::Left(repositories.into_iter()).into(),
    })
    .into_response())
}