##// END OF EJS Templates
Added file annotation template. Bumped version to 0.6.8. Changelog and changeset are now cleaned with js, it's still very beta.
marcink -
r193:50a39f92 default
parent child Browse files
Show More
@@ -0,0 +1,33 b''
1 <%!
2 from pylons_app.lib import filters
3 %>
4 <%inherit file="/base/base.html"/>
5
6 <%def name="title()">
7 ${_('Changeset')}
8 </%def>
9 <%def name="breadcrumbs()">
10 ${h.link_to(u'Home',h.url('/'))}
11 /
12 ${h.link_to(c.repo_name,h.url('changeset_home',repo_name=c.repo_name))}
13 /
14 ${_('changeset')}
15 </%def>
16 <%def name="page_nav()">
17 ${self.menu('changelog')}
18 </%def>
19
20 <%def name="main()">
21 <h2 class="no-link no-border">${_('Changeset')}</h2>
22 <div class="cs_files">
23 %for filenode in c.changeset.added:
24 <p class="cs_added">${filenode}</p>
25 %endfor
26 %for filenode in c.changeset.changed:
27 <p class="cs_changed">${filenode}</p>
28 %endfor
29 %for filenode in c.changeset.removed:
30 <p class="cs_removed">${filenode}</p>
31 %endfor
32 </div>
33 </%def> No newline at end of file
@@ -0,0 +1,44 b''
1 <%inherit file="/base/base.html"/>
2
3 <%def name="title()">
4 ${_('File annotate')}
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 ${self.menu('files')}
15 </%def>
16 <%def name="css()">
17 <link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
18 <link rel="stylesheet" href="/css/pygments.css" type="text/css" />
19 </%def>
20 <%def name="main()">
21 <h2 class="no-link no-border">${_('Annotate')}</h2>
22 <div id="files_data">
23 <h2>${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.file.path)}</h2>
24 <dl class="overview">
25 <dt>${_('Revision')}</dt>
26 <dd>r${c.file.last_changeset.revision}:${c.file.last_changeset._short}</dd>
27 <dt>${_('Size')}</dt>
28 <dd>${h.format_byte_size(c.file.size,binary=True)}</dd>
29 <dt>${_('Options')}</dt>
30 <dd>${h.link_to(_('source'),
31 h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))} / ${h.link_to(_('raw'),
32 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}</dd>
33 </dl>
34 <div id="body" class="codeblock">
35 <div class="code-header">
36 <div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${c.file.last_changeset._short}</div>
37 <div class="commit" style="font-size:70%">"${c.file_msg}"</div>
38 </div>
39 <div class="code-body">
40 ${h.pygmentize_annotation(c.annotate,c.repo_name)}
41 </div>
42 </div>
43 </div>
44 </%def> No newline at end of file
@@ -1,13 +1,13 b''
1 1 """
2 2 Hg app, a web based mercurial repository managment based on pylons
3 3 """
4 4
5 VERSION = (0, 6, 0, 'beta')
5 VERSION = (0, 6, 8, 'beta')
6 6
7 7 __version__ = '.'.join((str(each) for each in VERSION[:4]))
8 8
9 9 def get_version():
10 10 """
11 11 Returns shorter version (digit parts only) as string.
12 12 """
13 13 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,20 +1,23 b''
1 import logging
2
3 from pylons import request, response, session, tmpl_context as c, url, config, app_globals as g
1 from pylons import request, response, session, tmpl_context as c, url, config, \
2 app_globals as g
4 3 from pylons.controllers.util import abort, redirect
5
4 from pylons_app.lib.auth import LoginRequired
6 5 from pylons_app.lib.base import BaseController, render
7 6 from pylons_app.lib.utils import get_repo_slug
8 7 from pylons_app.model.hg_model import HgModel
8 import logging
9
10
9 11 log = logging.getLogger(__name__)
10 12
11 13 class ChangesetController(BaseController):
14
15 @LoginRequired()
12 16 def __before__(self):
13 c.repos_prefix = config['repos_name']
14 c.repo_name = get_repo_slug(request)
17 super(ChangesetController, self).__before__()
15 18
16 def index(self):
17 # Return a rendered template
18 #return render('/changeset.mako')
19 # or, return a string
20 return 'Hello World'
19 def index(self, revision):
20 hg_model = HgModel()
21 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
22
23 return render('changeset/changeset.html')
@@ -1,125 +1,125 b''
1 1 import os
2 2 import logging
3 3 from mercurial import ui, config, hg
4 4 from mercurial.error import RepoError
5 5 log = logging.getLogger(__name__)
6 6
7 7
8 8 def get_repo_slug(request):
9 9 path_info = request.environ.get('PATH_INFO')
10 10 uri_lst = path_info.split('/')
11 11 repo_name = uri_lst[1]
12 12 return repo_name
13 13
14 14 def is_mercurial(environ):
15 15 """
16 16 Returns True if request's target is mercurial server - header
17 17 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
18 18 """
19 19 http_accept = environ.get('HTTP_ACCEPT')
20 20 if http_accept and http_accept.startswith('application/mercurial'):
21 21 return True
22 22 return False
23 23
24 24 def check_repo_dir(paths):
25 25 repos_path = paths[0][1].split('/')
26 26 if repos_path[-1] in ['*', '**']:
27 27 repos_path = repos_path[:-1]
28 28 if repos_path[0] != '/':
29 29 repos_path[0] = '/'
30 30 if not os.path.isdir(os.path.join(*repos_path)):
31 31 raise Exception('Not a valid repository in %s' % paths[0][1])
32 32
33 33 def check_repo(repo_name, base_path):
34 34
35 35 repo_path = os.path.join(base_path, repo_name)
36 36
37 37 try:
38 38 r = hg.repository(ui.ui(), repo_path)
39 39 hg.verify(r)
40 40 #here we hnow that repo exists it was verified
41 41 log.info('%s repo is already created', repo_name)
42 42 return False
43 43 #raise Exception('Repo exists')
44 44 except RepoError:
45 45 log.info('%s repo is free for creation', repo_name)
46 46 #it means that there is no valid repo there...
47 47 return True
48 48
49 49 def make_ui(path='hgwebdir.config', checkpaths=True):
50 50 """
51 51 A funcion that will read python rc files and make an ui from read options
52 52
53 53 @param path: path to mercurial config file
54 54 """
55 55 if not os.path.isfile(path):
56 log.error('Unable to read config file %s' % path)
56 log.warning('Unable to read config file %s' % path)
57 57 return False
58 58 #propagated from mercurial documentation
59 59 sections = [
60 60 'alias',
61 61 'auth',
62 62 'decode/encode',
63 63 'defaults',
64 64 'diff',
65 65 'email',
66 66 'extensions',
67 67 'format',
68 68 'merge-patterns',
69 69 'merge-tools',
70 70 'hooks',
71 71 'http_proxy',
72 72 'smtp',
73 73 'patch',
74 74 'paths',
75 75 'profiling',
76 76 'server',
77 77 'trusted',
78 78 'ui',
79 79 'web',
80 80 ]
81 81
82 82 baseui = ui.ui()
83 83 cfg = config.config()
84 84 cfg.read(path)
85 85 if checkpaths:check_repo_dir(cfg.items('paths'))
86 86
87 87 for section in sections:
88 88 for k, v in cfg.items(section):
89 89 baseui.setconfig(section, k, v)
90 90
91 91 return baseui
92 92
93 93 def invalidate_cache(name, *args):
94 94 from beaker.cache import region_invalidate
95 95 log.info('INVALIDATING CACHE FOR %s', name)
96 96
97 97 """propaget our arguments to make sure invalidation works. First
98 98 argument has to be the name of cached func name give to cache decorator
99 99 without that the invalidation would not work"""
100 100 tmp = [name]
101 101 tmp.extend(args)
102 102 args = tuple(tmp)
103 103
104 104 if name == 'cached_repo_list':
105 105 from pylons_app.lib.base import _get_repos_cached
106 106 region_invalidate(_get_repos_cached, None, *args)
107 107
108 108 if name == 'full_changelog':
109 109 from pylons_app.controllers.changelog import _full_changelog_cached
110 110 region_invalidate(_full_changelog_cached, None, *args)
111 111
112 112 from vcs.backends.base import BaseChangeset
113 113 from vcs.utils.lazy import LazyProperty
114 114 class EmptyChangeset(BaseChangeset):
115 115
116 116 revision = -1
117 117
118 118 @LazyProperty
119 119 def raw_id(self):
120 120 """
121 121 Returns raw string identifing this changeset, useful for web
122 122 representation.
123 123 """
124 124 return '0' * 12
125 125
@@ -1,115 +1,80 b''
1 <%!
2 from pylons_app.lib import filters
3 %>
1 4 <%inherit file="/base/base.html"/>
2 5
3 6 <%def name="title()">
4 ${_('Repository managment')}
7 ${_('Changelog - %s') % c.repo_name}
5 8 </%def>
6 9 <%def name="breadcrumbs()">
7 10 ${h.link_to(u'Home',h.url('/'))}
8 11 /
9 12 ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
10 13 /
11 14 ${_('changelog')}
12 15 </%def>
13 16 <%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('changelog')}
17 ${self.menu('changelog')}
22 18 </%def>
23 19
24 20 <%def name="main()">
25 21
26 22 <h2 class="no-link no-border">${_('Changelog')} - ${_('showing ')} ${c.size} ${_('revisions')}</h2>
27 23 <noscript>${_('The revision graph only works with JavaScript-enabled browsers.')}</noscript>
28 <div>
29 ${h.form(h.url.current(),method='get')}
30 ${_('Show')}: ${h.text('size',size=5,value=c.size)} ${_('revisions')}
31 ${h.submit('','set')}
32 ${h.end_form()}
33 </div>
34 <div id="wrapper" style="height:${c.canvasheight}px">
35 <div style="float:left;height:${c.canvasheight}px">
36 <canvas id="graph" width="224" height="${c.canvasheight}"></canvas>
37 </div>
38 <div style="float:left;height:${c.canvasheight}px">
39 <ul id="graphnodes"></ul>
24
25 <div id="graph">
26 ##<div id="graph_nodes" style="height:1000px">
27 ## <canvas id="graph" width="160"></canvas>
28 ##</div>
29 <div id="graph_content">
30 <div class="container_header">
31 ${h.form(h.url.current(),method='get')}
32 ${_('Show')}: ${h.text('size',size=5,value=c.size)} ${_('revisions')}
33 ${h.submit('','set')}
34 ${h.end_form()}
35 </div>
36 %for cnt,cs in enumerate(c.pagination):
37 <div class="container">
38 <div class="left">
39 <div class="date">${_('commit')} ${cs.revision}: ${cs.raw_id}@${cs.date}</div>
40 <div class="author">${cs.author}</div>
41 <div id="chg_${cnt}" class="message">
42 ${h.link_to(cs.message,
43 h.url('changeset_home',repo_name=c.repo_name,revision=cs._short),
44 title=cs.message)}
45 </div>
46 <span class="logtags">
47 <span class="branchtag">${cs.branch}</span>
48 %for tag in cs.tags:
49 <span class="tagtag">${tag}</span>
50 %endfor
51 </span>
52 </div>
53 <div class="right">
54 <span class="removed" title="${_('removed')}">${len(cs.removed)}</span>
55 <span class="changed" title="${_('changed')}">${len(cs.changed)}</span>
56 <span class="added" title="${_('added')}">${len(cs.added)}</span>
57 </div>
58 </div>
59
60 %endfor
40 61 </div>
41 62 </div>
42 63
43 <script type="text/javascript" src="/js/graph.js"></script>
44 <script>
45 <!-- hide script content
46
47 var data = ${c.jsdata|n};
48 var graph = new Graph();
49 graph.scale(39);
50
51 graph.edge = function(x0, y0, x1, y1, color) {
52
53 this.setColor(color, 0.0, 0.65);
54 this.ctx.beginPath();
55 this.ctx.moveTo(x0, y0);
56 this.ctx.lineTo(x1, y1);
57 this.ctx.stroke();
58
59 }
60
61 var revlink = '<li style="_STYLE"><span class="desc">';
62 revlink += '<a class="list" href="/${c.repo_name}/changeset/_NODEID" title="_NODEID"><b>_DESC</b></a>';
63 revlink += '</span> _TAGS';
64 revlink += '<span class="info">_DATE, by _USER</span></li>';
64 ##<script type="text/javascript" src="/js/graph2.js"></script>
65 ##<script type="text/javascript" src="http://bitbucket-assets.s3.amazonaws.com/js/lib/bundle.160310Mar.js"></script>
66 ##
67 ##<script>
68 ##<!-- hide script content
69 ##
70 ##var jsdata = ${c.jsdata|n};
71 ##var r = new BranchRenderer();
72 ##r.render(jsdata);
65 73
66 graph.vertex = function(x, y, color, parity, cur) {
67
68 this.ctx.beginPath();
69 color = this.setColor(color, 0.25, 0.75);
70 this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
71 this.ctx.fill();
72
73 var bg = '<li class="bg parity' + parity + '"></li>';
74 var left = (this.columns + 1) * this.bg_height;
75 var nstyle = 'padding-left: ' + left + 'px;';
76 var item = revlink.replace(/_STYLE/, nstyle);
77 item = item.replace(/_PARITY/, 'parity' + parity);
78 item = item.replace(/_NODEID/, cur[0]);
79 item = item.replace(/_NODEID/, cur[0]);
80 item = item.replace(/_DESC/, cur[3]);
81 item = item.replace(/_USER/, cur[4]);
82 item = item.replace(/_DATE/, cur[5]);
83
84 var tagspan = '';
85 if (cur[7].length || (cur[6][0] != 'default' || cur[6][1])) {
86 tagspan = '<span class="logtags">';
87 if (cur[6][1]) {
88 tagspan += '<span class="branchtag" title="' + cur[6][0] + '">';
89 tagspan += cur[6][0] + '</span> ';
90 } else if (!cur[6][1] && cur[6][0] != 'default') {
91 tagspan += '<span class="inbranchtag" title="' + cur[6][0] + '">';
92 tagspan += cur[6][0] + '</span> ';
93 }
94 if (cur[7].length) {
95 for (var t in cur[7]) {
96 var tag = cur[7][t];
97 tagspan += '<span class="tagtag">' + tag + '</span> ';
98 }
99 }
100 tagspan += '</span>';
101 }
102
103 item = item.replace(/_TAGS/, tagspan);
104 return [bg, item];
105
106 }
74 ##// stop hiding script -->
75 ##</script>
107 76
108 graph.render(data);
109
110 // stop hiding script -->
111 </script>
112 77 <div>
113 78 <h2>${c.pagination.pager('$link_previous ~2~ $link_next')}</h2>
114 79 </div>
115 80 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now