From f9506811c70cce56ed89f40ebb32e43afc13765e Mon Sep 17 00:00:00 2001 From: Luka Hietala Date: Tue, 18 Nov 2025 21:30:53 +0200 Subject: [PATCH] tree traversal, ref shorthands, tree oids to commits --- app.py | 8 ++++++++ git/commit.py | 1 + git/ref.py | 2 ++ git/tree.py | 42 ++++++++++++++++++++++++++++++++++++++++++ templates/commit.html | 2 ++ templates/commits.html | 1 + templates/refs.html | 2 +- templates/tree.html | 14 ++++++++++++++ 8 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 git/tree.py create mode 100644 templates/tree.html diff --git a/app.py b/app.py index 487b947..eac0345 100644 --- a/app.py +++ b/app.py @@ -3,6 +3,7 @@ from flask import Flask, render_template, request from git.repo import get_bare_repos from git.commit import get_commits, get_commit from git.ref import get_refs +from git.tree import get_tree_items app = Flask(__name__) @@ -35,5 +36,12 @@ def repo_refs(repo_name): refs = get_refs(f"{repo_path}/{repo_name}") return render_template("refs.html", repo_name=repo_name, refs=refs) +@app.route("//tree", defaults={'path': ''}) +@app.route("//tree/") +def repo_tree_path(repo_name, path): + ref = request.args.get('ref', 'HEAD') + tree_items = get_tree_items(f"{repo_path}/{repo_name}", ref, path) + return render_template("tree.html", repo_name=repo_name, ref=ref, path=path, tree_items=tree_items) + if __name__ == "__main__": app.run(debug=True) \ No newline at end of file diff --git a/git/commit.py b/git/commit.py index 5607e8c..ba70b8c 100644 --- a/git/commit.py +++ b/git/commit.py @@ -69,6 +69,7 @@ def get_commit(path, commit_hash): 'message': commit.message.strip(), 'author': commit.author, 'committer': commit.committer, + 'tree_id': str(commit.tree.id), 'date': commit.commit_time, 'diff_stats': diff_stats, 'diff': diff.patch if diff else None diff --git a/git/ref.py b/git/ref.py index 1283bed..40a8312 100644 --- a/git/ref.py +++ b/git/ref.py @@ -8,6 +8,8 @@ def get_refs(path): ref = repo.lookup_reference(ref_name) refs.append({ 'name': ref.name, + 'shorthand': ref.shorthand, + # TODO: type, branch or tag 'target': str(ref.target) }) return refs \ No newline at end of file diff --git a/git/tree.py b/git/tree.py new file mode 100644 index 0000000..d17cc52 --- /dev/null +++ b/git/tree.py @@ -0,0 +1,42 @@ +import pygit2 as git + +# retrieves the tree items for a given ref and path +def get_tree_items(repo_path, ref="HEAD", tree_path=""): + repo = git.Repository(repo_path) + # TODO: dwim for ref + obj = repo.revparse_single(ref) + if obj.type == git.GIT_OBJECT_COMMIT: + tree = obj.tree + elif obj.type == git.GIT_OBJECT_TREE: + tree = obj + else: + # for other refs like tags, branches + commit = obj.peel(git.GIT_OBJECT_COMMIT) + tree = commit.tree + + # TODO: optimize path traversal, if possible + if tree_path: + # go down the tree to right path + parts = tree_path.rstrip('/').split('/') + for part in parts: + found = False + for entry in tree: + # look for matching tree entry + # if found, go to it + if entry.name == part and entry.type == git.GIT_OBJECT_TREE: + tree = repo.get(entry.id) + found = True + break + if not found: + return [] # path not found + + items = [] + for entry in tree: + item = { + 'name': entry.name, + 'type': 'tree' if entry.type == git.GIT_OBJECT_TREE else 'blob', + 'id': str(entry.id), + 'path': entry.name if not tree_path else f"{tree_path}/{entry.name}" + } + items.append(item) + return items \ No newline at end of file diff --git a/templates/commit.html b/templates/commit.html index ed8eeeb..80c35d7 100644 --- a/templates/commit.html +++ b/templates/commit.html @@ -4,6 +4,8 @@

Author: {{ commit.author.name }} <{{ commit.author.email }}>

Committer: {{ commit.committer.name }} <{{ commit.committer.email }}>

Date: {{ commit.date }}

+

Tree: {{ commit.tree_id }}

+

View Tree

Diff Stats

  • Files Changed: {{ commit.diff_stats.files_changed }}
  • diff --git a/templates/commits.html b/templates/commits.html index f9d63f7..e9ba28a 100644 --- a/templates/commits.html +++ b/templates/commits.html @@ -1,5 +1,6 @@ {% block content %}

    Commits for {{ repo_name }}

    +

    View Tree

      {% for commit in commits %}
    • diff --git a/templates/refs.html b/templates/refs.html index f4b8af2..0741998 100644 --- a/templates/refs.html +++ b/templates/refs.html @@ -3,7 +3,7 @@
        {% for ref in refs %}
      • - {{ ref.name }} - {{ ref.target }} + {{ ref.name }} - {{ ref.target }} - View Tree
      • {% endfor %}
      diff --git a/templates/tree.html b/templates/tree.html new file mode 100644 index 0000000..037a237 --- /dev/null +++ b/templates/tree.html @@ -0,0 +1,14 @@ +{% block content %} +

      Tree for {{ repo_name }} at {{ ref }}{% if path %} / {{ path }}{% endif %}

      +
        + {% for item in tree_items %} +
      • + {% if item.type == 'tree' %} + {{ item.name }} ({{ item.type }})/ + {% else %} + {{ item.name }} ({{ item.type }}) + {% endif %} +
      • + {% endfor %} +
      +{% endblock %} \ No newline at end of file -- 2.47.3