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, |
|
|
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. |
|
|
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 | 17 |
|
|
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> | |
|
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"> | |
|
29 | 31 | ${h.form(h.url.current(),method='get')} |
|
30 | 32 | ${_('Show')}: ${h.text('size',size=5,value=c.size)} ${_('revisions')} |
|
31 | 33 | ${h.submit('','set')} |
|
32 | 34 | ${h.end_form()} |
|
33 | 35 | </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> | |
|
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)} | |
|
37 | 45 | </div> |
|
38 | <div style="float:left;height:${c.canvasheight}px"> | |
|
39 | <ul id="graphnodes"></ul> | |
|
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> | |
|
40 | 57 | </div> |
|
41 | 58 | </div> |
|
42 | 59 | |
|
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>'; | |
|
65 | ||
|
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(); | |
|
60 | %endfor | |
|
61 | </div> | |
|
62 | </div> | |
|
72 | 63 | |
|
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]); | |
|
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); | |
|
83 | 73 | |
|
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 | } | |
|
74 | ##// stop hiding script --> | |
|
75 | ##</script> | |
|
102 | 76 | |
|
103 | item = item.replace(/_TAGS/, tagspan); | |
|
104 | return [bg, item]; | |
|
105 | ||
|
106 | } | |
|
107 | ||
|
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