~aw/patches

mygit: percent decode repository name v1 APPLIED

Johann Galle
Johann Galle: 5
 percent decode repository name
 handle empty repo correctly
 use repo_name filter everywhere
 handle shallow clones
 change name in some more places

 16 files changed, 93 insertions(+), 45 deletions(-)
Johann Galle
On 2021-03-15T20:01+01:00, Alex Wennerberg wrote:
 > Hi these look good! I'm on lunch break so I don't have time to look into this in detail -- but my only question is about the first patch -- the other 4 are ready to apply. Is there a way to do this that uses the tide crate itself rather than another crate? I havent checked but it seems like something I would expect the crate to be able to do

That is something I also wondered and tried to find on <https://docs.rs/tide>. Searching for "percent", "url", "encode" or "decode" did not bring anything up. Same results for the re-exportet http-types crate. But anyway we were already indirectly dependent on the percent-encoding crate [1], so the meaning of adding this to our Crates.toml only means that we can now also access it.

[1] more completely, we get this inverse dependency tree for it:

$ cargo tree -i percent-encoding
percent-encoding v2.1.0
├── askama_shared v0.11.1
│   ├── askama v0.10.5
│   │   ├── askama_tide v0.13.0
│   │   │   └── grifter v0.1.0
│   │   └── grifter v0.1.0
│   └── askama_derive v0.10.5 (proc-macro)
│       └── askama v0.10.5 (*)
├── cookie v0.14.4
│   └── http-types v2.10.0
│       ├── async-h1 v2.3.2
│       │   └── tide v0.16.0
│       │       ├── askama_tide v0.13.0 (*)
│       │       └── grifter v0.1.0
│       ├── async-sse v4.1.0
│       │   └── tide v0.16.0 (*)
│       ├── http-client v6.3.4
│       │   └── tide v0.16.0 (*)
│       └── tide v0.16.0 (*)
├── form_urlencoded v1.0.1
│   ├── serde_urlencoded v0.7.0
│   │   └── http-types v2.10.0 (*)
│   └── url v2.2.1
│       ├── git2 v0.13.17
│       │   └── grifter v0.1.0
│       └── http-types v2.10.00 (*)
├── grifter v0.1.0
├── serde_qs v0.7.2
│   └── http-types v2.10.0 (*)
└── url v2.2.1 (*)
Makes sense to me. I’ll merge these as soon as I get home

Alex
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~aw/patches/patches/21181/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH mygit 1/5] percent decode repository name Export this patch

Johann Galle
From: Johann150 <johann@qwertqwefsday.eu>

---
 Cargo.lock  | 1 +
 Cargo.toml  | 1 +
 src/main.rs | 3 +++
 3 files changed, 5 insertions(+)

diff --git a/Cargo.lock b/Cargo.lock
index 677d1e4..6da49e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1127,6 +1127,7 @@ dependencies = [
 "chrono",
 "git2",
 "once_cell",
 "percent-encoding",
 "pico-args",
 "pulldown-cmark",
 "serde",
diff --git a/Cargo.toml b/Cargo.toml
index 49c992f..9515e55 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,6 +15,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
chrono = "0.4"
git2 = {version="0.13", default-features = false}
once_cell = "1.7.2"
percent-encoding = "2.1"
pico-args = "0.4"
pulldown-cmark = "0.8"
serde = { version = "1.0", features = ["derive"] }
diff --git a/src/main.rs b/src/main.rs
index 6ad1499..9f264ab 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -84,6 +84,9 @@ struct RepoHomeTemplate {
}

fn repo_from_request(repo_name: &str) -> Result<Repository> {
    let repo_name = percent_encoding::percent_decode_str(repo_name)
        .decode_utf8_lossy()
        .into_owned();
    let repo_path = Path::new(&CONFIG.repo_directory).join(repo_name);
    // TODO CLEAN PATH! VERY IMPORTANT! DONT FORGET!
    let r = Repository::open(repo_path)?;
-- 
2.20.1
Hi these look good! I'm on lunch break so I don't have time to look into
this in detail -- but my only question is about the first patch -- the
other 4 are ready to apply. Is there a way to do this that uses the tide
crate itself rather than another crate? I havent checked but it seems
like something I would expect the crate to be able to do

Alex

On Mon Mar 15, 2021 at 10:57 AM PDT, Johann Galle wrote:

[PATCH mygit 2/5] handle empty repo correctly Export this patch

Johann Galle
From: Johann150 <johann@qwertqwefsday.eu>

---
 src/main.rs               | 31 +++++++++++++++++++++++++++++++
 templates/repo-empty.html |  6 ++++++
 2 files changed, 37 insertions(+)
 create mode 100644 templates/repo-empty.html

diff --git a/src/main.rs b/src/main.rs
index 9f264ab..f727880 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -83,6 +83,12 @@ struct RepoHomeTemplate {
    readme_text: String,
}

#[derive(Template)]
#[template(path = "repo-empty.html")]
struct RepoEmptyTemplate {
    repo: Repository,
}

fn repo_from_request(repo_name: &str) -> Result<Repository> {
    let repo_name = percent_encoding::percent_decode_str(repo_name)
        .decode_utf8_lossy()
@@ -103,6 +109,10 @@ async fn repo_home(req: Request<()>) -> tide::Result {
    }

    let repo = repo_from_request(&req.param("repo_name")?)?;
    if repo.is_empty().unwrap() {
        // we would not be able to find HEAD
        return Ok(RepoEmptyTemplate { repo }.into())
    }

    let readme_text = {
        let mut format = ReadmeFormat::Plaintext;
@@ -155,6 +165,13 @@ struct RepoLogTemplate<'a> {

async fn repo_log(req: Request<()>) -> tide::Result {
    let repo = repo_from_request(&req.param("repo_name")?)?;
    if repo.is_empty().unwrap() {
        // redirect to start page of repo
        let mut url = req.url().clone();
        url.path_segments_mut().unwrap().pop();
        return Ok(tide::Redirect::temporary(url.to_string()).into());
    }

    let mut revwalk = repo.revwalk()?;
    match req.param("ref") {
        Ok(r) => revwalk.push_ref(&format!("refs/heads/{}", r))?,
@@ -180,6 +197,13 @@ struct RepoRefTemplate<'a> {
}
async fn repo_refs(req: Request<()>) -> tide::Result {
    let repo = repo_from_request(&req.param("repo_name")?)?;
    if repo.is_empty().unwrap() {
        // redirect to start page of repo
        let mut url = req.url().clone();
        url.path_segments_mut().unwrap().pop();
        return Ok(tide::Redirect::temporary(url.to_string()).into());
    }

    let branches = repo
        .references()?
        .filter_map(|x| x.ok())
@@ -207,6 +231,13 @@ struct RepoTreeTemplate<'a> {
async fn repo_tree(req: Request<()>) -> tide::Result {
    // TODO handle subtrees
    let repo = repo_from_request(&req.param("repo_name")?)?;
    if repo.is_empty().unwrap() {
        // redirect to start page of repo
        let mut url = req.url().clone();
        url.path_segments_mut().unwrap().pop();
        return Ok(tide::Redirect::temporary(url.to_string()).into());
    }

    // TODO accept reference or commit id
    let spec = req.param("ref").unwrap_or("HEAD");
    let commit = repo.revparse_single(spec)?.peel_to_commit()?;
diff --git a/templates/repo-empty.html b/templates/repo-empty.html
new file mode 100644
index 0000000..70760c3
--- /dev/null
+++ b/templates/repo-empty.html
@@ -0,0 +1,6 @@
{% extends "base.html" %}

{% block content %}
  {% include "repo-navbar.html" %}
  <em>(This repository is empty.)</em>
{% endblock %}
-- 
2.20.1

[PATCH mygit 3/5] use repo_name filter everywhere Export this patch

Johann Galle
From: Johann150 <johann@qwertqwefsday.eu>

---
 templates/commit.html      | 5 ++---
 templates/log.html         | 3 +--
 templates/refs.html        | 5 ++---
 templates/repo-navbar.html | 4 ++--
 templates/repo.html        | 1 -
 templates/tree.html        | 1 -
 6 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/templates/commit.html b/templates/commit.html
index 5137b92..1e140c9 100644
--- a/templates/commit.html
+++ b/templates/commit.html
@@ -1,11 +1,10 @@
{% extends "base.html" %}

{% block content %}
  {% let name = repo.workdir().unwrap().file_name().unwrap().to_str().unwrap() %}
  {% include "repo-navbar.html" %}
  <b>Commit:</b> <div class="commit-hash">{{commit.id()}}</div> (<a href="/{{name}}/tree/{{parent.id()}}">tree</a>)
  <b>Commit:</b> <div class="commit-hash">{{commit.id()}}</div> (<a href="/{{repo|repo_name|urlencode_strict}}/tree/{{parent.id()}}">tree</a>)
  <br>
  <b>Parent:</b> <a href="/{{name}}/commit/{{parent.id()}}"><div class="commit-hash">{{parent.id()}}</div></a> (<a href="/{{name}}/tree/{{parent.id()}}">tree</a>)
  <b>Parent:</b> <a href="/{{repo|repo_name|urlencode_strict}}/commit/{{parent.id()}}"><div class="commit-hash">{{parent.id()}}</div></a> (<a href="/{{repo|repo_name|urlencode_strict}}/tree/{{parent.id()}}">tree</a>)
  <br>
  <b>Author:</b> {{commit.author().name().unwrap()}} &lt;<a href="mailto:{{commit.author().email().unwrap()}}">{{commit.author().email().unwrap()}}</a>&gt;
  <br>
diff --git a/templates/log.html b/templates/log.html
index 730d245..382196a 100644
--- a/templates/log.html
+++ b/templates/log.html
@@ -1,12 +1,11 @@
{% extends "base.html" %}

{% block content %}
  {% let name = repo.workdir().unwrap().file_name().unwrap().to_str().unwrap() %}
  {% include "repo-navbar.html" %}
  <table>
  {% for commit in commits %} 
  <tr>
    <td class="commit-hash"><a href="/{{name}}/commit/{{commit.id()}}">{{commit.id().to_string()[..7]}}</a></td>
    <td class="commit-hash"><a href="/{{repo|repo_name|urlencode_strict}}/commit/{{commit.id()}}">{{commit.id().to_string()[..7]}}</a></td>
    {% let summary = commit.summary().unwrap_or("")|truncate(72) %}
    <td class="commit-summary">{{summary}}</td>
    <td class="commit-author-email"><a href="mailto:{{commit.author().email().unwrap_or("")}}">{{commit.author().name().unwrap_or("")}}</a></td>
diff --git a/templates/refs.html b/templates/refs.html
index c048961..15b7bfc 100644
--- a/templates/refs.html
+++ b/templates/refs.html
@@ -1,14 +1,13 @@
{% extends "base.html" %}

{% block content %}
  {% let name = repo.workdir().unwrap().file_name().unwrap().to_str().unwrap() %}
  {% include "repo-navbar.html" %}
  <h2>Branches</h2>
  <table>
  {% for branch in branches %}
  <tr>
    <td class="git-reference">
    <a href="/{{name}}/log/{{branch.shorthand().unwrap()}}">{{ branch.shorthand().unwrap() }}</a>
    <a href="/{{repo|repo_name|urlencode_strict}}/log/{{branch.shorthand().unwrap()}}">{{ branch.shorthand().unwrap() }}</a>
    </td>
  </tr>
  {% endfor %}
@@ -16,7 +15,7 @@
  <h2>Tags</h2>
  <table>
  {% for tag in tags %}
  <tr><td class="git-reference"><a href="/{{name}}/commit/{{tag.shorthand().unwrap()}}">{{ tag.shorthand().unwrap() }}</a></td></tr>
  <tr><td class="git-reference"><a href="/{{repo|repo_name|urlencode_strict}}/commit/{{tag.shorthand().unwrap()}}">{{ tag.shorthand().unwrap() }}</a></td></tr>
  {% endfor %}
  </table>
{% endblock %}
diff --git a/templates/repo-navbar.html b/templates/repo-navbar.html
index effeb08..e902449 100644
--- a/templates/repo-navbar.html
+++ b/templates/repo-navbar.html
@@ -1,5 +1,5 @@
<h1><a href="/">index</a>/{{name}}</h1>
<h1><a href="/">index</a>/{{repo|repo_name}}</h1>
<div>My cool repo</div>
<div class="clone-url">git clone git.alexwennerberg.com/repo </div>
<div class="navbar"><a href="/{{name}}">README</a> |  <a href="/{{name}}/tree">tree</a> |  <a href="/{{name}}/log">log</a> |  <a href="/{{name}}/refs">refs</a></div>
<div class="navbar"><a href="/{{repo|repo_name|urlencode_strict}}">README</a> |  <a href="/{{repo|repo_name|urlencode_strict}}/tree">tree</a> |  <a href="/{{repo|repo_name|urlencode_strict}}/log">log</a> |  <a href="/{{repo|repo_name|urlencode_strict}}/refs">refs</a></div>
<hr class='thin'>
diff --git a/templates/repo.html b/templates/repo.html
index 85733e4..e2fcd0e 100644
--- a/templates/repo.html
+++ b/templates/repo.html
@@ -1,7 +1,6 @@
{% extends "base.html" %}

{% block content %}
  {% let name = repo.workdir().unwrap().file_name().unwrap().to_str().unwrap() %}
  {% include "repo-navbar.html" %}
  {{ readme_text|safe }}
{% endblock %}
diff --git a/templates/tree.html b/templates/tree.html
index 06a38c3..8f39c30 100644
--- a/templates/tree.html
+++ b/templates/tree.html
@@ -1,7 +1,6 @@
{% extends "base.html" %}

{% block content %}
  {% let name = repo.workdir().unwrap().file_name().unwrap().to_str().unwrap() %}
  {% include "repo-navbar.html" %}
  <table>
    {% for entry in tree %}
-- 
2.20.1

[PATCH mygit 4/5] handle shallow clones Export this patch

Johann Galle
From: Johann150 <johann@qwertqwefsday.eu>

Although unusual for a git server, encountering a shallow clone should
be handled correctly.
---
 src/main.rs | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index f727880..342248f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -111,7 +111,7 @@ async fn repo_home(req: Request<()>) -> tide::Result {
    let repo = repo_from_request(&req.param("repo_name")?)?;
    if repo.is_empty().unwrap() {
        // we would not be able to find HEAD
        return Ok(RepoEmptyTemplate { repo }.into())
        return Ok(RepoEmptyTemplate { repo }.into());
    }

    let readme_text = {
@@ -172,15 +172,26 @@ async fn repo_log(req: Request<()>) -> tide::Result {
        return Ok(tide::Redirect::temporary(url.to_string()).into());
    }

    let mut revwalk = repo.revwalk()?;
    match req.param("ref") {
        Ok(r) => revwalk.push_ref(&format!("refs/heads/{}", r))?,
        _ => revwalk.push_head()?,
    let commits = if repo.is_shallow() {
        tide::log::warn!("repository {:?} is only a shallow clone", repo.path());
        vec![repo.head()?.peel_to_commit().unwrap()]
    } else {
        let mut revwalk = repo.revwalk()?;
        match req.param("ref") {
            Ok(r) => revwalk.push_ref(&format!("refs/heads/{}", r))?,
            _ => revwalk.push_head()?,
        };

        // show newest commits first
        revwalk
            .set_sorting(git2::Sort::TIME | git2::Sort::REVERSE)
            .unwrap();

        revwalk
            .filter_map(|oid| repo.find_commit(oid.unwrap()).ok().clone()) // TODO error handling
            .take(100) // Only get first 100 commits
            .collect()
    };
    let commits = revwalk
        .filter_map(|oid| repo.find_commit(oid.unwrap()).ok().clone()) // TODO error handling
        .take(100) // Only get first 100 commits
        .collect();
    let tmpl = RepoLogTemplate {
        repo: &repo,
        commits,
-- 
2.20.1

[PATCH mygit 5/5] change name in some more places Export this patch

Johann Galle
From: Johann150 <johann@qwertqwefsday.eu>

---
 Cargo.lock                 | 40 +++++++++++++++++++-------------------
 mygit.toml => grifter.toml |  0
 src/main.rs                |  4 ++--
 templates/base.html        |  4 ++--
 4 files changed, 24 insertions(+), 24 deletions(-)
 rename mygit.toml => grifter.toml (100%)

diff --git a/Cargo.lock b/Cargo.lock
index 6da49e6..1decbdc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -863,6 +863,26 @@ dependencies = [
 "web-sys",
]

[[package]]
name = "grifter"
version = "0.1.0"
dependencies = [
 "anyhow",
 "askama",
 "askama_tide",
 "async-std",
 "chrono",
 "git2",
 "once_cell",
 "percent-encoding",
 "pico-args",
 "pulldown-cmark",
 "serde",
 "syntect",
 "tide",
 "toml",
]

[[package]]
name = "hashbrown"
version = "0.9.1"
@@ -1116,26 +1136,6 @@ version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"

[[package]]
name = "mygit"
version = "0.1.0"
dependencies = [
 "anyhow",
 "askama",
 "askama_tide",
 "async-std",
 "chrono",
 "git2",
 "once_cell",
 "percent-encoding",
 "pico-args",
 "pulldown-cmark",
 "serde",
 "syntect",
 "tide",
 "toml",
]

[[package]]
name = "nb-connect"
version = "1.0.3"
diff --git a/mygit.toml b/grifter.toml
similarity index 100%
rename from mygit.toml
rename to grifter.toml
diff --git a/src/main.rs b/src/main.rs
index 342248f..bd1242d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,7 +18,7 @@ pub struct Config {
}

const HELP: &str = "\
mygit
grifter

FLAGS:
  -h, --help            Prints help information
@@ -39,7 +39,7 @@ fn args() -> Config {
    }

    let toml_text =
        fs::read_to_string("mygit.toml").expect("expected configuration file mygit.toml");
        fs::read_to_string("grifter.toml").expect("expected configuration file grifter.toml");
    match toml::from_str(&toml_text) {
        Ok(config) => config,
        Err(e) => {
diff --git a/templates/base.html b/templates/base.html
index e47495c..10db5d2 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -13,9 +13,9 @@
    <div id="content">
      {% block content %}{% endblock %}
    </div>
  <hr class = "thin">
  <hr class="thin">
  <div class="footer">
  Server running <a href="git.alexwennerberg.com/mygit">mygit</a>
  Server running <a href="git.alexwennerberg.com/grifter">grifter</a>
  </div>
  </body>
</html>
-- 
2.20.1