🏡 index : ~doyle/rgit.git

author Jordan Doyle <jordan@doyle.la> 2022-07-06 2:45:18.0 +01:00:00
committer Jordan Doyle <jordan@doyle.la> 2022-07-06 2:45:18.0 +01:00:00
commit
873752f5abeaa212742551fafd67d66f7c0938ae [patch]
tree
41574800d11f96204e3e241e632296eb012dce1e
parent
fb33221b29832fa9e2d57c94cbc4f63a92c22dbd
download
873752f5abeaa212742551fafd67d66f7c0938ae.tar.gz

Implement repository refs page



Diff

 Cargo.lock               |  7 +++++++
 Cargo.toml               |  1 +
 src/git.rs               | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 statics/style.css        |  4 ++++
 src/methods/repo.rs      | 14 ++++++++++++--
 templates/repo/refs.html | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 4b7d73e..a9eda85 100644
--- a/Cargo.lock
+++ a/Cargo.lock
@@ -753,6 +753,12 @@
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"

[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"

[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1071,6 +1077,7 @@
 "git2",
 "hex",
 "humantime",
 "md5",
 "moka",
 "path-clean",
 "serde",
diff --git a/Cargo.toml b/Cargo.toml
index 9db11b0..9cc8330 100644
--- a/Cargo.toml
+++ a/Cargo.toml
@@ -14,6 +14,7 @@
git2 = "0.14"
hex = "0.4"
humantime = "2.1"
md5 = "0.7"
moka = { version = "0.9", features = ["future"] }
path-clean = "0.1"
serde = { version = "1.0", features = ["derive"] }
diff --git a/src/git.rs b/src/git.rs
index 943206f..090277e 100644
--- a/src/git.rs
+++ a/src/git.rs
@@ -16,6 +16,7 @@
pub struct Git {
    commits: moka::future::Cache<Oid, Arc<Commit>>,
    readme_cache: moka::future::Cache<PathBuf, Arc<str>>,
    refs: moka::future::Cache<PathBuf, Arc<Refs>>,
    repository_metadata: Arc<ArcSwapOption<RepositoryMetadataList>>,
}

@@ -24,6 +25,7 @@
        Self {
            commits: moka::future::Cache::new(100),
            readme_cache: moka::future::Cache::new(100),
            refs: moka::future::Cache::new(100),
            repository_metadata: Arc::new(ArcSwapOption::default()),
        }
    }
@@ -47,6 +49,43 @@
            .await
    }

    pub async fn get_refs<'a>(&'a self, repo: PathBuf) -> Arc<Refs> {
        self.refs
            .get_with(repo.clone(), async {
            tokio::task::spawn_blocking(move || {
                let repo = git2::Repository::open_bare(repo).unwrap();
                let refs = repo.references().unwrap();

                let mut built_refs = Refs::default();

                for ref_ in refs {
                    let ref_ = ref_.unwrap();

                    if ref_.is_branch() {
                        let commit = ref_.peel_to_commit().unwrap();

                        built_refs.branch.push(Branch {
                            name: ref_.shorthand().unwrap().to_string(),
                            commit: commit.into(),
                        });
                    } else if ref_.is_tag() {
                        let commit = ref_.peel_to_commit().unwrap();

                        built_refs.tag.push(Tag {
                            name: ref_.shorthand().unwrap().to_string(),
                            commit: commit.into(),
                        });
                    }
                }

                Arc::new(built_refs)
            })
            .await
            .unwrap()
        })
        .await
    }

    pub async fn get_readme(&self, repo: PathBuf) -> Arc<str> {
        self.readme_cache
            .get_with(repo.clone(), async {
@@ -99,6 +138,29 @@

        repos
    }
}

#[derive(Debug, Default)]
pub struct Refs {
    pub branch: Vec<Branch>,
    pub tag: Vec<Tag>,
}

#[derive(Debug)]
pub struct Branch {
    pub name: String,
    pub commit: Commit,
}

#[derive(Debug)]
pub struct Remote {
    pub name: String,
}

#[derive(Debug)]
pub struct Tag {
    pub name: String,
    pub commit: Commit,
}

#[derive(Debug)]
@@ -109,9 +171,11 @@
    pub last_modified: Duration,
}

#[derive(Debug)]
pub struct CommitUser {
    name: String,
    email: String,
    email_md5: String,
    time: String,
}

@@ -120,6 +184,7 @@
        CommitUser {
            name: v.name().unwrap().to_string(),
            email: v.email().unwrap().to_string(),
            email_md5: format!("{:x}", md5::compute(v.email_bytes())),
            time: OffsetDateTime::from_unix_timestamp(v.when().seconds())
                .unwrap()
                .to_string(),
@@ -134,6 +199,10 @@

    pub fn email(&self) -> &str {
        &self.email
    }

    pub fn email_md5(&self) -> &str {
        &self.email_md5
    }

    pub fn time(&self) -> &str {
@@ -141,6 +210,7 @@
    }
}

#[derive(Debug)]
pub struct Commit {
    author: CommitUser,
    committer: CommitUser,
diff --git a/statics/style.css b/statics/style.css
index 57cb54c..7a84891 100644
--- a/statics/style.css
+++ a/statics/style.css
@@ -29,6 +29,10 @@
    text-decoration: underline;
}

.mt-2 {
    margin-top: 2rem;
}

table { border-collapse: collapse; }
table.repositories { width: 100%; }
table.repositories a { color: black; }
diff --git a/src/methods/repo.rs b/src/methods/repo.rs
index 3926eff..7c9fe50 100644
--- a/src/methods/repo.rs
+++ a/src/methods/repo.rs
@@ -17,6 +17,7 @@
use tower::{util::BoxCloneService, Service};

use crate::{git::Commit, layers::UnwrapInfallible, Git};
use crate::git::Refs;

#[derive(Clone)]
pub struct Repository(pub PathBuf);
@@ -100,21 +101,28 @@
}

#[allow(clippy::unused_async)]
pub async fn handle_refs(Extension(repo): Extension<Repository>) -> Html<String> {
pub async fn handle_refs(
    Extension(repo): Extension<Repository>,
    Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
    Extension(git): Extension<Git>,
) -> Html<String> {
    #[derive(Template)]
    #[template(path = "repo/refs.html")]
    pub struct View {
        repo: Repository,
        refs: Arc<Refs>,
    }

    Html(View { repo }.render().unwrap())
    let refs = git.get_refs(repository_path).await;

    Html(View { repo, refs }.render().unwrap())
}

#[allow(clippy::unused_async)]
pub async fn handle_about(
    Extension(repo): Extension<Repository>,
    Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
    Extension(git): Extension<Git>
    Extension(git): Extension<Git>,
) -> Html<String> {
    #[derive(Template)]
    #[template(path = "repo/about.html")]
diff --git a/templates/repo/refs.html b/templates/repo/refs.html
index efdfb77..dc8afc4 100644
--- a/templates/repo/refs.html
+++ a/templates/repo/refs.html
@@ -1,6 +1,55 @@
{% extends "repo/base.html" %}

{% block refs_nav_class %}active{% endblock %}

{% block content %}
<table class="repositories">
    <thead>
    <tr>
        <th>Branch</th>
        <th>Commit message</th>
        <th>Author</th>
        <th>Age</th>
    </tr>
    </thead>

    <tbody>
    {% for branch in refs.branch %}
    <tr>
        <td><a href="/{{ repo.display() }}/log/?h={{ branch.name }}">{{ branch.name }}</a></td>
        <td><a href="/{{ repo.display() }}/commit/?id={{ branch.commit.oid() }}">{{ branch.commit.summary() }}</a></td>
        <td>
            <img src="https://www.gravatar.com/avatar/{{ branch.commit.author().email_md5() }}?s=13&d=retro" width="13" height="13">
            {{ branch.commit.author().name() }}
        </td>
        <td>{{ branch.commit.author().time() }}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>

<table class="repositories mt-2">
    <thead>
    <tr>
        <th>Tag</th>
        <th>Download</th>
        <th>Author</th>
        <th>Age</th>
    </tr>
    </thead>

    <tbody>
    {% for tag in refs.tag %}
    <tr>
        <td><a href="/{{ repo.display() }}/tag/?h={{ tag.name }}">{{ tag.name }}</a></td>
        <td></td>
        <td>
            <img src="https://www.gravatar.com/avatar/{{ tag.commit.author().email_md5() }}?s=13&d=retro" width="13" height="13">
            {{ tag.commit.author().name() }}
        </td>
        <td>{{ tag.commit.author().time() }}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>
{% endblock %}