##// 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 Hg app, a web based mercurial repository managment based on pylons
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 __version__ = '.'.join((str(each) for each in VERSION[:4]))
7 __version__ = '.'.join((str(each) for each in VERSION[:4]))
8
8
9 def get_version():
9 def get_version():
10 """
10 """
11 Returns shorter version (digit parts only) as string.
11 Returns shorter version (digit parts only) as string.
12 """
12 """
13 return '.'.join((str(each) for each in VERSION[:3]))
13 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,20 +1,23 b''
1 import logging
1 from pylons import request, response, session, tmpl_context as c, url, config, \
2
2 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
3 from pylons.controllers.util import abort, redirect
5
4 from pylons_app.lib.auth import LoginRequired
6 from pylons_app.lib.base import BaseController, render
5 from pylons_app.lib.base import BaseController, render
7 from pylons_app.lib.utils import get_repo_slug
6 from pylons_app.lib.utils import get_repo_slug
8 from pylons_app.model.hg_model import HgModel
7 from pylons_app.model.hg_model import HgModel
8 import logging
9
10
9 log = logging.getLogger(__name__)
11 log = logging.getLogger(__name__)
10
12
11 class ChangesetController(BaseController):
13 class ChangesetController(BaseController):
14
15 @LoginRequired()
12 def __before__(self):
16 def __before__(self):
13 c.repos_prefix = config['repos_name']
17 super(ChangesetController, self).__before__()
14 c.repo_name = get_repo_slug(request)
15
18
16 def index(self):
19 def index(self, revision):
17 # Return a rendered template
20 hg_model = HgModel()
18 #return render('/changeset.mako')
21 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
19 # or, return a string
22
20 return 'Hello World'
23 return render('changeset/changeset.html')
@@ -1,125 +1,125 b''
1 import os
1 import os
2 import logging
2 import logging
3 from mercurial import ui, config, hg
3 from mercurial import ui, config, hg
4 from mercurial.error import RepoError
4 from mercurial.error import RepoError
5 log = logging.getLogger(__name__)
5 log = logging.getLogger(__name__)
6
6
7
7
8 def get_repo_slug(request):
8 def get_repo_slug(request):
9 path_info = request.environ.get('PATH_INFO')
9 path_info = request.environ.get('PATH_INFO')
10 uri_lst = path_info.split('/')
10 uri_lst = path_info.split('/')
11 repo_name = uri_lst[1]
11 repo_name = uri_lst[1]
12 return repo_name
12 return repo_name
13
13
14 def is_mercurial(environ):
14 def is_mercurial(environ):
15 """
15 """
16 Returns True if request's target is mercurial server - header
16 Returns True if request's target is mercurial server - header
17 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
17 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
18 """
18 """
19 http_accept = environ.get('HTTP_ACCEPT')
19 http_accept = environ.get('HTTP_ACCEPT')
20 if http_accept and http_accept.startswith('application/mercurial'):
20 if http_accept and http_accept.startswith('application/mercurial'):
21 return True
21 return True
22 return False
22 return False
23
23
24 def check_repo_dir(paths):
24 def check_repo_dir(paths):
25 repos_path = paths[0][1].split('/')
25 repos_path = paths[0][1].split('/')
26 if repos_path[-1] in ['*', '**']:
26 if repos_path[-1] in ['*', '**']:
27 repos_path = repos_path[:-1]
27 repos_path = repos_path[:-1]
28 if repos_path[0] != '/':
28 if repos_path[0] != '/':
29 repos_path[0] = '/'
29 repos_path[0] = '/'
30 if not os.path.isdir(os.path.join(*repos_path)):
30 if not os.path.isdir(os.path.join(*repos_path)):
31 raise Exception('Not a valid repository in %s' % paths[0][1])
31 raise Exception('Not a valid repository in %s' % paths[0][1])
32
32
33 def check_repo(repo_name, base_path):
33 def check_repo(repo_name, base_path):
34
34
35 repo_path = os.path.join(base_path, repo_name)
35 repo_path = os.path.join(base_path, repo_name)
36
36
37 try:
37 try:
38 r = hg.repository(ui.ui(), repo_path)
38 r = hg.repository(ui.ui(), repo_path)
39 hg.verify(r)
39 hg.verify(r)
40 #here we hnow that repo exists it was verified
40 #here we hnow that repo exists it was verified
41 log.info('%s repo is already created', repo_name)
41 log.info('%s repo is already created', repo_name)
42 return False
42 return False
43 #raise Exception('Repo exists')
43 #raise Exception('Repo exists')
44 except RepoError:
44 except RepoError:
45 log.info('%s repo is free for creation', repo_name)
45 log.info('%s repo is free for creation', repo_name)
46 #it means that there is no valid repo there...
46 #it means that there is no valid repo there...
47 return True
47 return True
48
48
49 def make_ui(path='hgwebdir.config', checkpaths=True):
49 def make_ui(path='hgwebdir.config', checkpaths=True):
50 """
50 """
51 A funcion that will read python rc files and make an ui from read options
51 A funcion that will read python rc files and make an ui from read options
52
52
53 @param path: path to mercurial config file
53 @param path: path to mercurial config file
54 """
54 """
55 if not os.path.isfile(path):
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 return False
57 return False
58 #propagated from mercurial documentation
58 #propagated from mercurial documentation
59 sections = [
59 sections = [
60 'alias',
60 'alias',
61 'auth',
61 'auth',
62 'decode/encode',
62 'decode/encode',
63 'defaults',
63 'defaults',
64 'diff',
64 'diff',
65 'email',
65 'email',
66 'extensions',
66 'extensions',
67 'format',
67 'format',
68 'merge-patterns',
68 'merge-patterns',
69 'merge-tools',
69 'merge-tools',
70 'hooks',
70 'hooks',
71 'http_proxy',
71 'http_proxy',
72 'smtp',
72 'smtp',
73 'patch',
73 'patch',
74 'paths',
74 'paths',
75 'profiling',
75 'profiling',
76 'server',
76 'server',
77 'trusted',
77 'trusted',
78 'ui',
78 'ui',
79 'web',
79 'web',
80 ]
80 ]
81
81
82 baseui = ui.ui()
82 baseui = ui.ui()
83 cfg = config.config()
83 cfg = config.config()
84 cfg.read(path)
84 cfg.read(path)
85 if checkpaths:check_repo_dir(cfg.items('paths'))
85 if checkpaths:check_repo_dir(cfg.items('paths'))
86
86
87 for section in sections:
87 for section in sections:
88 for k, v in cfg.items(section):
88 for k, v in cfg.items(section):
89 baseui.setconfig(section, k, v)
89 baseui.setconfig(section, k, v)
90
90
91 return baseui
91 return baseui
92
92
93 def invalidate_cache(name, *args):
93 def invalidate_cache(name, *args):
94 from beaker.cache import region_invalidate
94 from beaker.cache import region_invalidate
95 log.info('INVALIDATING CACHE FOR %s', name)
95 log.info('INVALIDATING CACHE FOR %s', name)
96
96
97 """propaget our arguments to make sure invalidation works. First
97 """propaget our arguments to make sure invalidation works. First
98 argument has to be the name of cached func name give to cache decorator
98 argument has to be the name of cached func name give to cache decorator
99 without that the invalidation would not work"""
99 without that the invalidation would not work"""
100 tmp = [name]
100 tmp = [name]
101 tmp.extend(args)
101 tmp.extend(args)
102 args = tuple(tmp)
102 args = tuple(tmp)
103
103
104 if name == 'cached_repo_list':
104 if name == 'cached_repo_list':
105 from pylons_app.lib.base import _get_repos_cached
105 from pylons_app.lib.base import _get_repos_cached
106 region_invalidate(_get_repos_cached, None, *args)
106 region_invalidate(_get_repos_cached, None, *args)
107
107
108 if name == 'full_changelog':
108 if name == 'full_changelog':
109 from pylons_app.controllers.changelog import _full_changelog_cached
109 from pylons_app.controllers.changelog import _full_changelog_cached
110 region_invalidate(_full_changelog_cached, None, *args)
110 region_invalidate(_full_changelog_cached, None, *args)
111
111
112 from vcs.backends.base import BaseChangeset
112 from vcs.backends.base import BaseChangeset
113 from vcs.utils.lazy import LazyProperty
113 from vcs.utils.lazy import LazyProperty
114 class EmptyChangeset(BaseChangeset):
114 class EmptyChangeset(BaseChangeset):
115
115
116 revision = -1
116 revision = -1
117
117
118 @LazyProperty
118 @LazyProperty
119 def raw_id(self):
119 def raw_id(self):
120 """
120 """
121 Returns raw string identifing this changeset, useful for web
121 Returns raw string identifing this changeset, useful for web
122 representation.
122 representation.
123 """
123 """
124 return '0' * 12
124 return '0' * 12
125
125
@@ -1,115 +1,80 b''
1 <%!
2 from pylons_app.lib import filters
3 %>
1 <%inherit file="/base/base.html"/>
4 <%inherit file="/base/base.html"/>
2
5
3 <%def name="title()">
6 <%def name="title()">
4 ${_('Repository managment')}
7 ${_('Changelog - %s') % c.repo_name}
5 </%def>
8 </%def>
6 <%def name="breadcrumbs()">
9 <%def name="breadcrumbs()">
7 ${h.link_to(u'Home',h.url('/'))}
10 ${h.link_to(u'Home',h.url('/'))}
8 /
11 /
9 ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
12 ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
10 /
13 /
11 ${_('changelog')}
14 ${_('changelog')}
12 </%def>
15 </%def>
13 <%def name="page_nav()">
16 <%def name="page_nav()">
14 <form action="log">
17 ${self.menu('changelog')}
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')}
22 </%def>
18 </%def>
23
19
24 <%def name="main()">
20 <%def name="main()">
25
21
26 <h2 class="no-link no-border">${_('Changelog')} - ${_('showing ')} ${c.size} ${_('revisions')}</h2>
22 <h2 class="no-link no-border">${_('Changelog')} - ${_('showing ')} ${c.size} ${_('revisions')}</h2>
27 <noscript>${_('The revision graph only works with JavaScript-enabled browsers.')}</noscript>
23 <noscript>${_('The revision graph only works with JavaScript-enabled browsers.')}</noscript>
28 <div>
24
29 ${h.form(h.url.current(),method='get')}
25 <div id="graph">
30 ${_('Show')}: ${h.text('size',size=5,value=c.size)} ${_('revisions')}
26 ##<div id="graph_nodes" style="height:1000px">
31 ${h.submit('','set')}
27 ## <canvas id="graph" width="160"></canvas>
32 ${h.end_form()}
28 ##</div>
33 </div>
29 <div id="graph_content">
34 <div id="wrapper" style="height:${c.canvasheight}px">
30 <div class="container_header">
35 <div style="float:left;height:${c.canvasheight}px">
31 ${h.form(h.url.current(),method='get')}
36 <canvas id="graph" width="224" height="${c.canvasheight}"></canvas>
32 ${_('Show')}: ${h.text('size',size=5,value=c.size)} ${_('revisions')}
37 </div>
33 ${h.submit('','set')}
38 <div style="float:left;height:${c.canvasheight}px">
34 ${h.end_form()}
39 <ul id="graphnodes"></ul>
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 </div>
61 </div>
41 </div>
62 </div>
42
63
43 <script type="text/javascript" src="/js/graph.js"></script>
64 ##<script type="text/javascript" src="/js/graph2.js"></script>
44 <script>
65 ##<script type="text/javascript" src="http://bitbucket-assets.s3.amazonaws.com/js/lib/bundle.160310Mar.js"></script>
45 <!-- hide script content
66 ##
46
67 ##<script>
47 var data = ${c.jsdata|n};
68 ##<!-- hide script content
48 var graph = new Graph();
69 ##
49 graph.scale(39);
70 ##var jsdata = ${c.jsdata|n};
50
71 ##var r = new BranchRenderer();
51 graph.edge = function(x0, y0, x1, y1, color) {
72 ##r.render(jsdata);
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>';
65
73
66 graph.vertex = function(x, y, color, parity, cur) {
74 ##// stop hiding script -->
67
75 ##</script>
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 }
107
76
108 graph.render(data);
109
110 // stop hiding script -->
111 </script>
112 <div>
77 <div>
113 <h2>${c.pagination.pager('$link_previous ~2~ $link_next')}</h2>
78 <h2>${c.pagination.pager('$link_previous ~2~ $link_next')}</h2>
114 </div>
79 </div>
115 </%def> No newline at end of file
80 </%def>
General Comments 0
You need to be logged in to leave comments. Login now