diff --git a/app.py b/app.py
index eac0345..290e17b 100644
--- a/app.py
+++ b/app.py
from git.commit import get_commits, get_commit
from git.ref import get_refs
from git.tree import get_tree_items
+from git.blob import get_blob
app = Flask(__name__)
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)
+@app.route("/<repo_name>/blob/<path:path>")
+def repo_blob_path(repo_name, path):
+ ref = request.args.get('ref', 'HEAD')
+ blob = get_blob(f"{repo_path}/{repo_name}", ref, path)
+ return render_template("blob.html", repo_name=repo_name, ref=ref, path=path, blob=blob)
+
if __name__ == "__main__":
app.run(debug=True)
\ No newline at end of file
diff --git a/git/blob.py b/git/blob.py
new file mode 100644
index 0000000..96496a6
--- /dev/null
+++ b/git/blob.py
+import pygit2 as git
+
+# retrieves a blob content for given ref and path
+def get_blob(repo_path, ref="HEAD", blob_path=""):
+ repo = git.Repository(repo_path)
+ 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:
+ commit = obj.peel(git.GIT_OBJECT_COMMIT)
+ tree = commit.tree
+
+ # traverse to the blob path
+ # TODO: improve the code, just quick and dirty
+ if blob_path:
+ parts = blob_path.rstrip('/').split('/')
+ for part in parts:
+ found = False
+ for entry in tree:
+ if entry.name == part:
+ if entry.type == git.GIT_OBJECT_BLOB:
+ blob = repo.get(entry.id)
+ return {
+ 'name': entry.name,
+ 'id': str(entry.id),
+ 'path': blob_path,
+ 'size': blob.size,
+ 'is_binary': blob.is_binary,
+ 'content': blob.data.decode('utf-8', errors='replace')
+ }
+ elif entry.type == git.GIT_OBJECT_TREE:
+ tree = repo.get(entry.id)
+ found = True
+ break
+ if not found:
+ return None # path not found
+ return None # blob not found
diff --git a/git/tree.py b/git/tree.py
index d17cc52..46f6522 100644
--- a/git/tree.py
+++ b/git/tree.py
item = {
'name': entry.name,
'type': 'tree' if entry.type == git.GIT_OBJECT_TREE else 'blob',
+ 'size': entry.size if entry.type == git.GIT_OBJECT_BLOB else None,
'id': str(entry.id),
'path': entry.name if not tree_path else f"{tree_path}/{entry.name}"
}
diff --git a/templates/blob.html b/templates/blob.html
new file mode 100644
index 0000000..72352fc
--- /dev/null
+++ b/templates/blob.html
+{% block content %}
+<h1>Blob: {{ blob.name }}</h1>
+<p>Blob hash: {{ blob.id }}</p>
+<p>Size: {{ blob.size }} bytes</p>
+<h2>Content:</h2>
+{% if blob.is_binary %}
+ <pre>Binary...</pre>
+{% else %}
+<pre>{{ blob.content }}</pre>
+{% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/commit.html b/templates/commit.html
index 80c35d7..c95a0d8 100644
--- a/templates/commit.html
+++ b/templates/commit.html
<p>Author: {{ commit.author.name }} <{{ commit.author.email }}></p>
<p>Committer: {{ commit.committer.name }} <{{ commit.committer.email }}></p>
<p>Date: {{ commit.date }}</p>
- <p>Tree: {{ commit.tree_id }}</p>
+ <p>Tree: <a href="{{ url_for('repo_tree_path', repo_name=repo_name, path='') }}?ref={{ commit.tree_id }}">{{ commit.tree_id }}</a></p>
<p><a href="{{ url_for('repo_tree_path', repo_name=repo_name, path='') }}?ref={{ commit.id }}">View Tree</a></p>
<h2>Diff Stats</h2>
<ul>
diff --git a/templates/tree.html b/templates/tree.html
index 037a237..9bee483 100644
--- a/templates/tree.html
+++ b/templates/tree.html
{% if item.type == 'tree' %}
<a href="{{ url_for('repo_tree_path', repo_name=repo_name, path=item.path) }}?ref={{ ref }}">{{ item.name }} ({{ item.type }})/</a>
{% else %}
- {{ item.name }} ({{ item.type }})
+ <a href="{{ url_for('repo_blob_path', repo_name=repo_name, path=item.path) }}?ref={{ ref }}">{{ item.name }} ({{ item.type }}) {{ item.size }} bytes</a>
{% endif %}
</li>
{% endfor %}