changeset 129:42d46deb124d

implemented simple diffs for history of files.
author Marcin Kuzminski <marcin@python-works.com>
date Tue, 04 May 2010 00:54:00 +0200
parents 9deb6f1d5b90
children ffddbd80649e
files pylons_app/config/routing.py pylons_app/controllers/files.py pylons_app/public/css/pygments_diff.css pylons_app/templates/files/file_diff.html pylons_app/templates/files/files_source.html
diffstat 5 files changed, 143 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/pylons_app/config/routing.py	Mon May 03 21:59:01 2010 +0200
+++ b/pylons_app/config/routing.py	Tue May 04 00:54:00 2010 +0200
@@ -39,6 +39,6 @@
     map.connect('tags_home', '/{repo_name}/tags', controller='tags')
     map.connect('graph_home', '/{repo_name}/graph/{revision}', controller='graph', revision='tip')    
     map.connect('files_home', '/{repo_name}/files/{revision}/{f_path:.*}', controller='files', revision='tip', f_path='')
-    
+    map.connect('files_diff_home', '/{repo_name}/diff/{f_path:.*}', controller='files', action='diff', revision='tip', f_path='')
 
     return map
--- a/pylons_app/controllers/files.py	Mon May 03 21:59:01 2010 +0200
+++ b/pylons_app/controllers/files.py	Tue May 04 00:54:00 2010 +0200
@@ -25,13 +25,29 @@
         c.file_history = self._get_history(repo, c.files_list, f_path)
         return render('files/files.html')
 
-
+    def diff(self, repo_name, f_path):
+        hg_model = HgModel()
+        diff1 = request.GET.get('diff1')
+        diff2 = request.GET.get('diff2')
+        c.f_path = f_path
+        c.repo = hg_model.get_repo(c.repo_name)
+        c.changeset_1 = c.repo.get_changeset(diff1)
+        c.changeset_2 = c.repo.get_changeset(diff2)
+        
+        c.file_1 = c.changeset_1.get_node(f_path).content
+        c.file_2 = c.changeset_2.get_node(f_path).content
+        c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1._short)
+        c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2._short)
+        from difflib import unified_diff
+        d = unified_diff(c.file_1.splitlines(1), c.file_2.splitlines(1))
+        c.diff = ''.join(d)
+        return render('files/file_diff.html')
+    
     def _get_history(self, repo, node, f_path):
         from vcs.nodes import NodeKind
         if not node.kind is NodeKind.FILE:
             return []
-        changesets = list(node.history)
-        changesets.reverse()
+        changesets = node.history
         hist_l = []
         for chs in changesets:
             n_desc = 'r%s:%s' % (chs.revision, chs._short)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pylons_app/public/css/pygments_diff.css	Tue May 04 00:54:00 2010 +0200
@@ -0,0 +1,87 @@
+div.codeblock {
+    overflow: auto;
+    padding: 0px;
+    border: 1px solid #ccc;
+    background: #f8f8f8;
+    font-size: 100%;
+    line-height: 100%;
+    /* new */
+    line-height: 125%;
+}
+
+.code-diff {
+    padding: 0px;
+    margin-top: 5px;
+    margin-bottom: 5px;
+    border-left: 2px solid #ccc;
+}
+.code-diff pre, .linenodiv pre { 
+	padding: 5px;
+    margin: 0;
+}
+.linenos a { text-decoration: none; }
+
+
+.code { display: block;}
+
+.code-diff .hll { background-color: #ffffcc }
+.code-diff  { background: #ffffff; }
+.code-diff .c { color: #888888 } /* Comment */
+.code-diff .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.code-diff .k { color: #008800; font-weight: bold } /* Keyword */
+.code-diff .cm { color: #888888 } /* Comment.Multiline */
+.code-diff .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
+.code-diff .c1 { color: #888888 } /* Comment.Single */
+.code-diff .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
+.code-diff .gd { color: #000000; background-color: #ffdddd;width: 300px  } /* Generic.Deleted */
+.code-diff .ge { font-style: italic } /* Generic.Emph */
+.code-diff .gr { color: #aa0000 } /* Generic.Error */
+.code-diff .gh { color: #303030 } /* Generic.Heading */
+.code-diff .gi { color: #000000; background-color: #ddffdd;width: 100% } /* Generic.Inserted */
+.code-diff .go { color: #888888 } /* Generic.Output */
+.code-diff .gp { color: #555555 } /* Generic.Prompt */
+.code-diff .gs { font-weight: bold } /* Generic.Strong */
+.code-diff .gu { color: #606060 } /* Generic.Subheading */
+.code-diff .gt { color: #aa0000 } /* Generic.Traceback */
+.code-diff .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
+.code-diff .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
+.code-diff .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
+.code-diff .kp { color: #008800 } /* Keyword.Pseudo */
+.code-diff .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
+.code-diff .kt { color: #888888; font-weight: bold } /* Keyword.Type */
+.code-diff .m { color: #0000DD; font-weight: bold } /* Literal.Number */
+.code-diff .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
+.code-diff .na { color: #336699 } /* Name.Attribute */
+.code-diff .nb { color: #003388 } /* Name.Builtin */
+.code-diff .nc { color: #bb0066; font-weight: bold } /* Name.Class */
+.code-diff .no { color: #003366; font-weight: bold } /* Name.Constant */
+.code-diff .nd { color: #555555 } /* Name.Decorator */
+.code-diff .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
+.code-diff .nf { color: #0066bb; font-weight: bold } /* Name.Function */
+.code-diff .nl { color: #336699; font-style: italic } /* Name.Label */
+.code-diff .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
+.code-diff .py { color: #336699; font-weight: bold } /* Name.Property */
+.code-diff .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
+.code-diff .nv { color: #336699 } /* Name.Variable */
+.code-diff .ow { color: #008800 } /* Operator.Word */
+.code-diff .w { color: #bbbbbb } /* Text.Whitespace */
+.code-diff .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
+.code-diff .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
+.code-diff .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
+.code-diff .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
+.code-diff .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
+.code-diff .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
+.code-diff .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
+.code-diff .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
+.code-diff .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
+.code-diff .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
+.code-diff .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
+.code-diff .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
+.code-diff .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
+.code-diff .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
+.code-diff .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
+.code-diff .bp { color: #003388 } /* Name.Builtin.Pseudo */
+.code-diff .vc { color: #336699 } /* Name.Variable.Class */
+.code-diff .vg { color: #dd7700 } /* Name.Variable.Global */
+.code-diff .vi { color: #3333bb } /* Name.Variable.Instance */
+.code-diff .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pylons_app/templates/files/file_diff.html	Tue May 04 00:54:00 2010 +0200
@@ -0,0 +1,35 @@
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${_('Repository managment')}
+</%def>
+<%def name="breadcrumbs()">
+    ${h.link_to(u'Home',h.url('/'))}
+    / 
+    ${h.link_to(c.repo_name,h.url('files_home',repo_name=c.repo_name))}
+    /
+    ${_('files')}
+</%def>
+<%def name="page_nav()">
+        <form action="log">
+            <dl class="search">
+                <dt><label>Search: </label></dt>
+                <dd><input type="text" name="rev" /></dd>
+            </dl>
+        </form>
+
+		${self.menu('files')}     
+</%def>
+<%def name="css()">
+<link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
+<link rel="stylesheet" href="/css/pygments_diff.css" type="text/css" />
+</%def>
+<div></div>
+<%def name="main()">
+    <h2 class="no-link no-border">${'%s: %s@%s %s %s' % (_('File diff'),c.f_path,c.diff2,'&rarr;',c.diff1)|n}</h2>
+	<div id="files_data">
+		<div id="body" class="codeblock">
+			${h.pygmentize(c.diff,linenos=True,anchorlinenos=True,cssclass="code-diff")}
+		</div>
+	</div>
+</%def>    
\ No newline at end of file
--- a/pylons_app/templates/files/files_source.html	Mon May 03 21:59:01 2010 +0200
+++ b/pylons_app/templates/files/files_source.html	Tue May 04 00:54:00 2010 +0200
@@ -7,7 +7,7 @@
 	<dd>history  / annotate  / raw  </dd>
 	<dt>${_('History')}</dt>
 	<dd>
-		${h.form(h.url.current())}
+		${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='GET')}
 		${h.hidden('diff2',c.files_list.changeset._short)}
 		${h.select('diff1','',c.file_history)}
 		${h.submit('diff','diff')}