##// END OF EJS Templates
implemented simple diffs for history of files.
marcink -
r129:42d46deb default
parent child Browse files
Show More
@@ -0,0 +1,87 b''
1 div.codeblock {
2 overflow: auto;
3 padding: 0px;
4 border: 1px solid #ccc;
5 background: #f8f8f8;
6 font-size: 100%;
7 line-height: 100%;
8 /* new */
9 line-height: 125%;
10 }
11
12 .code-diff {
13 padding: 0px;
14 margin-top: 5px;
15 margin-bottom: 5px;
16 border-left: 2px solid #ccc;
17 }
18 .code-diff pre, .linenodiv pre {
19 padding: 5px;
20 margin: 0;
21 }
22 .linenos a { text-decoration: none; }
23
24
25 .code { display: block;}
26
27 .code-diff .hll { background-color: #ffffcc }
28 .code-diff { background: #ffffff; }
29 .code-diff .c { color: #888888 } /* Comment */
30 .code-diff .err { color: #a61717; background-color: #e3d2d2 } /* Error */
31 .code-diff .k { color: #008800; font-weight: bold } /* Keyword */
32 .code-diff .cm { color: #888888 } /* Comment.Multiline */
33 .code-diff .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
34 .code-diff .c1 { color: #888888 } /* Comment.Single */
35 .code-diff .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
36 .code-diff .gd { color: #000000; background-color: #ffdddd;width: 300px } /* Generic.Deleted */
37 .code-diff .ge { font-style: italic } /* Generic.Emph */
38 .code-diff .gr { color: #aa0000 } /* Generic.Error */
39 .code-diff .gh { color: #303030 } /* Generic.Heading */
40 .code-diff .gi { color: #000000; background-color: #ddffdd;width: 100% } /* Generic.Inserted */
41 .code-diff .go { color: #888888 } /* Generic.Output */
42 .code-diff .gp { color: #555555 } /* Generic.Prompt */
43 .code-diff .gs { font-weight: bold } /* Generic.Strong */
44 .code-diff .gu { color: #606060 } /* Generic.Subheading */
45 .code-diff .gt { color: #aa0000 } /* Generic.Traceback */
46 .code-diff .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
47 .code-diff .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
48 .code-diff .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
49 .code-diff .kp { color: #008800 } /* Keyword.Pseudo */
50 .code-diff .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
51 .code-diff .kt { color: #888888; font-weight: bold } /* Keyword.Type */
52 .code-diff .m { color: #0000DD; font-weight: bold } /* Literal.Number */
53 .code-diff .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
54 .code-diff .na { color: #336699 } /* Name.Attribute */
55 .code-diff .nb { color: #003388 } /* Name.Builtin */
56 .code-diff .nc { color: #bb0066; font-weight: bold } /* Name.Class */
57 .code-diff .no { color: #003366; font-weight: bold } /* Name.Constant */
58 .code-diff .nd { color: #555555 } /* Name.Decorator */
59 .code-diff .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
60 .code-diff .nf { color: #0066bb; font-weight: bold } /* Name.Function */
61 .code-diff .nl { color: #336699; font-style: italic } /* Name.Label */
62 .code-diff .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
63 .code-diff .py { color: #336699; font-weight: bold } /* Name.Property */
64 .code-diff .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
65 .code-diff .nv { color: #336699 } /* Name.Variable */
66 .code-diff .ow { color: #008800 } /* Operator.Word */
67 .code-diff .w { color: #bbbbbb } /* Text.Whitespace */
68 .code-diff .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
69 .code-diff .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
70 .code-diff .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
71 .code-diff .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
72 .code-diff .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
73 .code-diff .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
74 .code-diff .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
75 .code-diff .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
76 .code-diff .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
77 .code-diff .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
78 .code-diff .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
79 .code-diff .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
80 .code-diff .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
81 .code-diff .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
82 .code-diff .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
83 .code-diff .bp { color: #003388 } /* Name.Builtin.Pseudo */
84 .code-diff .vc { color: #336699 } /* Name.Variable.Class */
85 .code-diff .vg { color: #dd7700 } /* Name.Variable.Global */
86 .code-diff .vi { color: #3333bb } /* Name.Variable.Instance */
87 .code-diff .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
@@ -0,0 +1,35 b''
1 <%inherit file="/base/base.html"/>
2
3 <%def name="title()">
4 ${_('Repository managment')}
5 </%def>
6 <%def name="breadcrumbs()">
7 ${h.link_to(u'Home',h.url('/'))}
8 /
9 ${h.link_to(c.repo_name,h.url('files_home',repo_name=c.repo_name))}
10 /
11 ${_('files')}
12 </%def>
13 <%def name="page_nav()">
14 <form action="log">
15 <dl class="search">
16 <dt><label>Search: </label></dt>
17 <dd><input type="text" name="rev" /></dd>
18 </dl>
19 </form>
20
21 ${self.menu('files')}
22 </%def>
23 <%def name="css()">
24 <link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
25 <link rel="stylesheet" href="/css/pygments_diff.css" type="text/css" />
26 </%def>
27 <div></div>
28 <%def name="main()">
29 <h2 class="no-link no-border">${'%s: %s@%s %s %s' % (_('File diff'),c.f_path,c.diff2,'&rarr;',c.diff1)|n}</h2>
30 <div id="files_data">
31 <div id="body" class="codeblock">
32 ${h.pygmentize(c.diff,linenos=True,anchorlinenos=True,cssclass="code-diff")}
33 </div>
34 </div>
35 </%def> No newline at end of file
@@ -1,44 +1,44 b''
1 """Routes configuration
1 """Routes configuration
2
2
3 The more specific and detailed routes should be defined first so they
3 The more specific and detailed routes should be defined first so they
4 may take precedent over the more generic routes. For more information
4 may take precedent over the more generic routes. For more information
5 refer to the routes manual at http://routes.groovie.org/docs/
5 refer to the routes manual at http://routes.groovie.org/docs/
6 """
6 """
7 from routes import Mapper
7 from routes import Mapper
8
8
9 def make_map(config):
9 def make_map(config):
10 """Create, configure and return the routes Mapper"""
10 """Create, configure and return the routes Mapper"""
11 map = Mapper(directory=config['pylons.paths']['controllers'],
11 map = Mapper(directory=config['pylons.paths']['controllers'],
12 always_scan=config['debug'])
12 always_scan=config['debug'])
13 map.minimization = False
13 map.minimization = False
14 map.explicit = False
14 map.explicit = False
15
15
16 # The ErrorController route (handles 404/500 error pages); it should
16 # The ErrorController route (handles 404/500 error pages); it should
17 # likely stay at the top, ensuring it can always be resolved
17 # likely stay at the top, ensuring it can always be resolved
18 map.connect('/error/{action}', controller='error')
18 map.connect('/error/{action}', controller='error')
19 map.connect('/error/{action}/{id}', controller='error')
19 map.connect('/error/{action}/{id}', controller='error')
20
20
21 # CUSTOM ROUTES HERE
21 # CUSTOM ROUTES HERE
22 map.connect('hg_home', '/', controller='hg', action='index')
22 map.connect('hg_home', '/', controller='hg', action='index')
23
23
24
24
25 #REST controllers
25 #REST controllers
26 map.resource('repo', 'repos', path_prefix='/_admin')
26 map.resource('repo', 'repos', path_prefix='/_admin')
27 map.resource('user', 'users', path_prefix='/_admin')
27 map.resource('user', 'users', path_prefix='/_admin')
28
28
29 #ADMIN
29 #ADMIN
30 with map.submapper(path_prefix='/_admin', controller='admin') as m:
30 with map.submapper(path_prefix='/_admin', controller='admin') as m:
31 m.connect('admin_home', '/', action='index')#main page
31 m.connect('admin_home', '/', action='index')#main page
32 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', action='add_repo')
32 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', action='add_repo')
33
33
34
34
35 map.connect('changeset_home', '/{repo_name}/changeset/{revision}', controller='changeset', revision='tip')
35 map.connect('changeset_home', '/{repo_name}/changeset/{revision}', controller='changeset', revision='tip')
36 map.connect('summary_home', '/{repo_name}/summary', controller='summary')
36 map.connect('summary_home', '/{repo_name}/summary', controller='summary')
37 map.connect('changelog_home', '/{repo_name}/changelog/{revision}', controller='changelog', revision='tip')
37 map.connect('changelog_home', '/{repo_name}/changelog/{revision}', controller='changelog', revision='tip')
38 map.connect('branches_home', '/{repo_name}/branches', controller='branches')
38 map.connect('branches_home', '/{repo_name}/branches', controller='branches')
39 map.connect('tags_home', '/{repo_name}/tags', controller='tags')
39 map.connect('tags_home', '/{repo_name}/tags', controller='tags')
40 map.connect('graph_home', '/{repo_name}/graph/{revision}', controller='graph', revision='tip')
40 map.connect('graph_home', '/{repo_name}/graph/{revision}', controller='graph', revision='tip')
41 map.connect('files_home', '/{repo_name}/files/{revision}/{f_path:.*}', controller='files', revision='tip', f_path='')
41 map.connect('files_home', '/{repo_name}/files/{revision}/{f_path:.*}', controller='files', revision='tip', f_path='')
42
42 map.connect('files_diff_home', '/{repo_name}/diff/{f_path:.*}', controller='files', action='diff', revision='tip', f_path='')
43
43
44 return map
44 return map
@@ -1,39 +1,55 b''
1 import logging
1 import logging
2
2
3 from pylons import request, response, session, tmpl_context as c, url, config, app_globals as g
3 from pylons import request, response, session, tmpl_context as c, url, config, app_globals as g
4 from pylons.controllers.util import abort, redirect
4 from pylons.controllers.util import abort, redirect
5
5
6 from pylons_app.lib.base import BaseController, render
6 from pylons_app.lib.base import BaseController, render
7 from pylons_app.lib.utils import get_repo_slug
7 from pylons_app.lib.utils import get_repo_slug
8 from pylons_app.model.hg_model import HgModel
8 from pylons_app.model.hg_model import HgModel
9 log = logging.getLogger(__name__)
9 log = logging.getLogger(__name__)
10
10
11 class FilesController(BaseController):
11 class FilesController(BaseController):
12 def __before__(self):
12 def __before__(self):
13 c.repos_prefix = config['repos_name']
13 c.repos_prefix = config['repos_name']
14 c.repo_name = get_repo_slug(request)
14 c.repo_name = get_repo_slug(request)
15
15
16 def index(self, repo_name, revision, f_path):
16 def index(self, repo_name, revision, f_path):
17 hg_model = HgModel()
17 hg_model = HgModel()
18 c.repo = repo = hg_model.get_repo(c.repo_name)
18 c.repo = repo = hg_model.get_repo(c.repo_name)
19 c.cur_rev = revision
19 c.cur_rev = revision
20 c.f_path = f_path
20 c.f_path = f_path
21 c.changeset = repo.get_changeset(repo._get_revision(revision))
21 c.changeset = repo.get_changeset(repo._get_revision(revision))
22
22
23 c.files_list = c.changeset.get_node(f_path)
23 c.files_list = c.changeset.get_node(f_path)
24
24
25 c.file_history = self._get_history(repo, c.files_list, f_path)
25 c.file_history = self._get_history(repo, c.files_list, f_path)
26 return render('files/files.html')
26 return render('files/files.html')
27
27
28
28 def diff(self, repo_name, f_path):
29 hg_model = HgModel()
30 diff1 = request.GET.get('diff1')
31 diff2 = request.GET.get('diff2')
32 c.f_path = f_path
33 c.repo = hg_model.get_repo(c.repo_name)
34 c.changeset_1 = c.repo.get_changeset(diff1)
35 c.changeset_2 = c.repo.get_changeset(diff2)
36
37 c.file_1 = c.changeset_1.get_node(f_path).content
38 c.file_2 = c.changeset_2.get_node(f_path).content
39 c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1._short)
40 c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2._short)
41 from difflib import unified_diff
42 d = unified_diff(c.file_1.splitlines(1), c.file_2.splitlines(1))
43 c.diff = ''.join(d)
44 return render('files/file_diff.html')
45
29 def _get_history(self, repo, node, f_path):
46 def _get_history(self, repo, node, f_path):
30 from vcs.nodes import NodeKind
47 from vcs.nodes import NodeKind
31 if not node.kind is NodeKind.FILE:
48 if not node.kind is NodeKind.FILE:
32 return []
49 return []
33 changesets = list(node.history)
50 changesets = node.history
34 changesets.reverse()
35 hist_l = []
51 hist_l = []
36 for chs in changesets:
52 for chs in changesets:
37 n_desc = 'r%s:%s' % (chs.revision, chs._short)
53 n_desc = 'r%s:%s' % (chs.revision, chs._short)
38 hist_l.append((chs._short, n_desc,))
54 hist_l.append((chs._short, n_desc,))
39 return hist_l
55 return hist_l
@@ -1,20 +1,20 b''
1 <dl class="overview">
1 <dl class="overview">
2 <dt>${_('Revision')}</dt>
2 <dt>${_('Revision')}</dt>
3 <dd>r${c.files_list.changeset.revision}:${c.files_list.changeset._short}</dd>
3 <dd>r${c.files_list.changeset.revision}:${c.files_list.changeset._short}</dd>
4 <dt>${_('Size')}</dt>
4 <dt>${_('Size')}</dt>
5 <dd>${h.filesizeformat(c.files_list.size)}</dd>
5 <dd>${h.filesizeformat(c.files_list.size)}</dd>
6 <dt>${_('Options')}</dt>
6 <dt>${_('Options')}</dt>
7 <dd>history / annotate / raw </dd>
7 <dd>history / annotate / raw </dd>
8 <dt>${_('History')}</dt>
8 <dt>${_('History')}</dt>
9 <dd>
9 <dd>
10 ${h.form(h.url.current())}
10 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='GET')}
11 ${h.hidden('diff2',c.files_list.changeset._short)}
11 ${h.hidden('diff2',c.files_list.changeset._short)}
12 ${h.select('diff1','',c.file_history)}
12 ${h.select('diff1','',c.file_history)}
13 ${h.submit('diff','diff')}
13 ${h.submit('diff','diff')}
14 ${h.end_form()}
14 ${h.end_form()}
15 </dd>
15 </dd>
16
16
17 </dl>
17 </dl>
18 <div id="body" class="codeblock">
18 <div id="body" class="codeblock">
19 ${h.pygmentize(c.files_list.content,linenos=True,anchorlinenos=True,cssclass="code-highlight")}
19 ${h.pygmentize(c.files_list.content,linenos=True,anchorlinenos=True,cssclass="code-highlight")}
20 </div> No newline at end of file
20 </div>
General Comments 0
You need to be logged in to leave comments. Login now