From f8eb80d336b4b4bd8c09ccf15f57e29dc75a7da0 Mon Sep 17 00:00:00 2001
From: Jonas Haag <jonas@lophus.org>
Date: Thu, 2 Jun 2011 01:08:04 +0200
Subject: [PATCH] Made the tree view navigatable, added a blob view

---
 klaus.py                 | 41 ++++++++++++++++++++++++++++++----------
 repo.py                  | 14 +++++++++-----
 templates/view_blob.html | 12 ++++++++++++
 templates/view_tree.html | 11 ++++++++---
 4 files changed, 60 insertions(+), 18 deletions(-)
 create mode 100644 templates/view_blob.html

diff --git a/klaus.py b/klaus.py
index 8823636..f4624c1 100644
--- a/klaus.py
+++ b/klaus.py
@@ -1,4 +1,5 @@
 import os
+import stat
 import time
 from functools import wraps
 
@@ -78,8 +79,6 @@ def get_repo(name):
         raise HttpError(404, 'No repository named "%s"' % name)
 
 def get_commit(repo, id):
-    if isinstance(repo, basestring):
-        repo = get_repo(repo)
     try:
         commit = repo[id]
         if not isinstance(commit, Commit):
@@ -88,23 +87,45 @@ def get_commit(repo, id):
     except KeyError:
         raise HttpError(404, '"%s" has no commit "%s"' % (repo.name, id))
 
+def get_branch_or_commit(repo, id):
+    try:
+        return repo.get_branch(id)
+    except KeyError:
+        return get_commit(repo, id)
+
+def get_tree_or_blob_url(repo, commit_id, tree_entry):
+    if tree_entry.mode & stat.S_IFDIR:
+        view = 'view_tree'
+    else:
+        view = 'view_blob'
+    return app.build_url(view,
+        repo=repo.name, commit_id=commit_id, path=tree_entry.path)
+
 @app.route('/')
 def repo_list(env):
     return {'repos' : app.repos.items()}
 
 @app.route('/:repo:/')
 def view_repo(env, repo):
-    redirect_to = app.build_url('view_tree', repo=repo, commit_id='master')
+    redirect_to = app.build_url('view_tree', repo=repo, commit_id='master', path='')
     return '302 Move On', {'Location' : redirect_to}, ''
 
-@app.route('/:repo:/tree/:commit_id:/')
-def view_tree(env, repo, commit_id):
+@app.route('/:repo:/tree/:commit_id:/(?P<path>.*)')
+def view_tree(env, repo, commit_id, path):
     repo = get_repo(repo)
-    try:
-        commit = repo.get_branch(commit_id)
-    except KeyError:
-        commit = get_commit(repo, commit_id)
-    return {'repo' : repo, 'commit' : commit}
+    commit = get_branch_or_commit(repo, commit_id)
+    files = ((name, get_tree_or_blob_url(repo, commit_id, entry))
+             for name, entry in repo.listdir(commit, path))
+    return {'repo' : repo, 'commit_id' : commit_id,
+            'files' : files, 'path' : path}
+
+@app.route('/:repo:/blob/:commit_id:/(?P<path>.*)')
+def view_blob(env, repo, commit_id, path):
+    repo = get_repo(repo)
+    commit = get_branch_or_commit(repo, commit_id)
+    directory, filename = os.path.split(path)
+    blob = repo[repo.get_tree(commit, directory)[filename][1]]
+    return {'repo' : repo, 'blob' : blob, 'path' : path, 'commit_id' : commit_id}
 
 @app.route('/:repo:/commit/:id:/')
 def view_commit(env, repo, id):
diff --git a/repo.py b/repo.py
index af34db8..4d3b10e 100644
--- a/repo.py
+++ b/repo.py
@@ -20,12 +20,16 @@ class RepoWrapper(dulwich.repo.Repo):
             head = self[head.parents[0]]
             max_commits -= 1
 
-    def listdir(self, commit=None, root=None):
+    def get_tree(self, commit, path):
         tree = self[commit.tree]
-        if root is not None:
-            for directory in root.split('/'):
-                tree = self[tree[directory].sha]
-        return tree.iteritems()
+        if path:
+            for directory in path.split('/'):
+                tree = self[tree[directory][1]]
+        return tree
+
+    def listdir(self, commit, root=None):
+        tree = self.get_tree(commit, root)
+        return ((entry.path, entry.in_path(root)) for entry in tree.iteritems())
 
     def commit_diff(self, commit):
         parent = self[commit.parents[0]]
diff --git a/templates/view_blob.html b/templates/view_blob.html
new file mode 100644
index 0000000..b339de0
--- /dev/null
+++ b/templates/view_blob.html
@@ -0,0 +1,12 @@
+{% if path %}
+  {% set title = '%s in %s/%s' % (path, repo.name, commit_id) %}
+{% else %}
+  {% set title = '%s/%s' % (repo.name, commit_id) %}
+{% endif %}
+
+{% extends 'base.html' %}
+{% block content %}
+
+{{ blob.data|pygmentize }}
+
+{% endblock %}
diff --git a/templates/view_tree.html b/templates/view_tree.html
index 13a3249..bde19ca 100644
--- a/templates/view_tree.html
+++ b/templates/view_tree.html
@@ -1,4 +1,9 @@
-{% set title = repo.name %}
+{% if path %}
+  {% set title = '%s in %s/%s' % (path, repo.name, commit_id) %}
+{% else %}
+  {% set title = '%s/%s' % (repo.name, commit_id) %}
+{% endif %}
+
 {% extends 'base.html' %}
 {% block content %}
 
@@ -17,8 +22,8 @@
 </ul>
 
 <ul class=tree>
-{% for file, _, _ in repo.listdir(commit=commit) %}
-  <li>{{ file }}</li>
+{% for name, url in files %}
+  <li><a href="{{ url }}">{{ name }}</a></li>
 {% endfor %}
 </ul>
 
-- 
GitLab