🏡 index : ~doyle/rgit.git

author Jordan Doyle <jordan@doyle.la> 2024-09-29 13:44:31.0 +04:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-09-29 13:44:31.0 +04:00:00
commit
755876c268f288e104abd126ee7c2c3e8ac4fcb3 [patch]
tree
3d3f1640e2beff38f75fa925400723f529e2422b
parent
626743ff6175a8e57501463f47b1d067bb8c3931
download
755876c268f288e104abd126ee7c2c3e8ac4fcb3.tar.gz

Add support for submodules



Diff

 src/git.rs               | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
 templates/repo/tree.html |   6 ++++++
 2 files changed, 77 insertions(+), 30 deletions(-)

diff --git a/src/git.rs b/src/git.rs
index b091838..67eda1b 100644
--- a/src/git.rs
+++ a/src/git.rs
@@ -1,15 +1,3 @@
use std::{
    borrow::Cow,
    collections::VecDeque,
    ffi::OsStr,
    fmt::{self, Arguments, Write},
    io::ErrorKind,
    path::{Path, PathBuf},
    str::FromStr,
    sync::Arc,
    time::Duration,
};

use anyhow::{anyhow, Context, Result};
use axum::response::IntoResponse;
use bytes::{buf::Writer, BufMut, Bytes, BytesMut};
@@ -19,13 +7,26 @@
    actor::SignatureRef,
    bstr::{BStr, BString, ByteSlice, ByteVec},
    diff::blob::{platform::prepare_diff::Operation, Sink},
    object::tree::EntryKind,
    object::Kind,
    objs::tree::EntryRef,
    prelude::TreeEntryRefExt,
    traverse::tree::visit::Action,
    ObjectId, ThreadSafeRepository,
    url::Scheme,
    ObjectId, ThreadSafeRepository, Url,
};
use moka::future::Cache;
use std::{
    borrow::Cow,
    collections::{BTreeMap, VecDeque},
    ffi::OsStr,
    fmt::{self, Arguments, Write},
    io::ErrorKind,
    path::{Path, PathBuf},
    str::FromStr,
    sync::Arc,
    time::Duration,
};
use tar::Builder;
use time::{OffsetDateTime, UtcOffset};
use tracing::{error, instrument, warn};
@@ -106,6 +107,7 @@
}

impl OpenRepository {
    #[allow(clippy::too_many_lines)]
    pub async fn path(
        self: Arc<Self>,
        path: Option<PathBuf>,
@@ -182,32 +184,62 @@
            }

            let mut tree_items = Vec::new();
            let submodules = repo
                .submodules()?
                .into_iter()
                .flatten()
                .filter_map(|v| Some((v.name().to_path_lossy().to_path_buf(), v.url().ok()?)))
                .collect::<BTreeMap<_, _>>();

            for item in tree.iter() {
                let item = item?;
                let object = item
                    .object()
                    .context("Expected item in tree to be object but it wasn't")?;

                let path = path
                    .clone()
                    .unwrap_or_default()
                    .join(item.filename().to_path_lossy());

                match item.mode().kind() {
                    EntryKind::Tree
                    | EntryKind::Blob
                    | EntryKind::BlobExecutable
                    | EntryKind::Link => {
                        let object = item
                            .object()
                            .context("Expected item in tree to be object but it wasn't")?;

                        tree_items.push(match object.kind {
                            Kind::Blob => TreeItem::File(File {
                                mode: item.mode().0,
                                size: object.into_blob().data.len(),
                                path,
                                name: item.filename().to_string(),
                            }),
                            Kind::Tree => TreeItem::Tree(Tree {
                                mode: item.mode().0,
                                path,
                                name: item.filename().to_string(),
                            }),
                            _ => continue,
                        });
                    }
                    EntryKind::Commit => {
                        if let Some(mut url) = submodules.get(path.as_path()).cloned() {
                            if matches!(url.scheme, Scheme::Git | Scheme::Ssh) {
                                url.scheme = Scheme::Https;
                            }

                            tree_items.push(TreeItem::Submodule(Submodule {
                                mode: item.mode().0,
                                name: item.filename().to_string(),
                                url,
                                oid: item.object_id(),
                            }));

                tree_items.push(match object.kind {
                    Kind::Blob => TreeItem::File(File {
                        mode: item.mode().0,
                        size: object.into_blob().data.len(),
                        path,
                        name: item.filename().to_string(),
                    }),
                    Kind::Tree => TreeItem::Tree(Tree {
                        mode: item.mode().0,
                        path,
                        name: item.filename().to_string(),
                    }),
                    _ => continue,
                });
                            continue;
                        }
                    }
                }
            }

            Ok(PathDestination::Tree(tree_items))
@@ -561,6 +593,15 @@
pub enum TreeItem {
    Tree(Tree),
    File(File),
    Submodule(Submodule),
}

#[derive(Debug)]
pub struct Submodule {
    pub mode: u16,
    pub name: String,
    pub url: Url,
    pub oid: ObjectId,
}

#[derive(Debug)]
diff --git a/templates/repo/tree.html b/templates/repo/tree.html
index a17b137..faa1be6 100644
--- a/templates/repo/tree.html
+++ a/templates/repo/tree.html
@@ -28,6 +28,12 @@
        <td><pre><a href="/{{ repo.display() }}/tree/{{ file.path.display() }}{{ query }}">{{ file.name }}</a></pre></td>
        <td><pre>{{ file.size }}</pre></td>
        <td></td>

        {%- when crate::git::TreeItem::Submodule with (submodule) -%}
        <td><pre>{{ submodule.mode|file_perms }}</pre></td>
        <td><pre>🔗 <a href="{{ submodule.url }}">{{ submodule.name }}</a> @ {{ submodule.oid.to_hex_with_len(7) }}</pre></td>
        <td></td>
        <td></td>
        {%- endmatch %}
    </tr>
    {% endfor -%}