##// END OF EJS Templates
added version generation to pylons_app and showed it into template. Propagated baseController with some data for acces into each controller. Fixed simplehg middleware to get proper name of application
marcink -
r185:3380ca40 default
parent child Browse files
Show More
@@ -0,0 +1,13 b''
1 """
2 Hg app, a web based mercurial repository managment based on pylons
3 """
4
5 VERSION = (0, 6, 0, 'beta')
6
7 __version__ = '.'.join((str(each) for each in VERSION[:4]))
8
9 def get_version():
10 """
11 Returns shorter version (digit parts only) as string.
12 """
13 return '.'.join((str(each) for each in VERSION[:3]))
@@ -1,28 +1,37 b''
1 1 """The base Controller API
2 2
3 3 Provides the BaseController class for subclassing.
4 4 """
5 from beaker.cache import cache_region
6 from pylons import config, tmpl_context as c, request, session
5 7 from pylons.controllers import WSGIController
6 8 from pylons.templating import render_mako as render
9 from pylons_app.lib.auth import LoginRequired, AuthUser
10 from pylons_app.lib.utils import get_repo_slug
7 11 from pylons_app.model import meta
8 from beaker.cache import cache_region
9 from pylons import tmpl_context as c
10 12 from pylons_app.model.hg_model import HgModel
13 from pylons_app import get_version
11 14
12 15 @cache_region('long_term', 'cached_repo_list')
13 16 def _get_repos_cached():
14 17 return [rep for rep in HgModel().get_repos()]
15 18
16 19 class BaseController(WSGIController):
17
20
21 def __before__(self):
22 c.hg_app_version = get_version()
23 c.repos_prefix = config['hg_app_name']
24 c.repo_name = get_repo_slug(request)
25 c.hg_app_user = session.get('hg_app_user', AuthUser())
26 c.cached_repo_list = _get_repos_cached()
27 self.sa = meta.Session
28
18 29 def __call__(self, environ, start_response):
19 30 """Invoke the Controller"""
20 31 # WSGIController.__call__ dispatches to the Controller method
21 32 # the request is routed to. This routing information is
22 33 # available in environ['pylons.routes_dict']
23 c.cached_repo_list = _get_repos_cached()
24 self.sa = meta.Session
25 34 try:
26 35 return WSGIController.__call__(self, environ, start_response)
27 36 finally:
28 37 meta.Session.remove()
@@ -1,86 +1,86 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 #
4 4 # Copyright (c) 2010 marcink. All rights reserved.
5 5 #
6 6 """
7 7 Created on 2010-04-28
8 8
9 9 @author: marcink
10 10 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
11 11 It's implemented with basic auth function
12 12 """
13 13
14 14 from mercurial.hgweb import hgweb
15 15 from mercurial.hgweb.request import wsgiapplication
16 16 from paste.auth.basic import AuthBasicAuthenticator
17 17 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
18 18 from pylons_app.lib.utils import is_mercurial
19 19 from pylons_app.lib.auth import authfunc
20 20 from pylons_app.lib.utils import make_ui, invalidate_cache
21 21 from webob.exc import HTTPNotFound
22 22 import os
23 23
24 24 class SimpleHg(object):
25 25
26 26 def __init__(self, application, config):
27 27 self.application = application
28 28 self.config = config
29 29 #authenticate this mercurial request using
30 realm = '%s %s' % (config['repos_name'], 'mercurial repository')
30 realm = '%s %s' % (config['hg_app_name'], 'mercurial repository')
31 31 self.authenticate = AuthBasicAuthenticator(realm, authfunc)
32 32
33 33 def __call__(self, environ, start_response):
34 34 if not is_mercurial(environ):
35 35 return self.application(environ, start_response)
36 36 else:
37 37 #===================================================================
38 38 # AUTHENTICATE THIS MERCURIAL REQUEST
39 39 #===================================================================
40 40 username = REMOTE_USER(environ)
41 41 if not username:
42 42 result = self.authenticate(environ)
43 43 if isinstance(result, str):
44 44 AUTH_TYPE.update(environ, 'basic')
45 45 REMOTE_USER.update(environ, result)
46 46 else:
47 47 return result.wsgi_application(environ, start_response)
48 48
49 49 try:
50 50 repo_name = environ['PATH_INFO'].split('/')[1]
51 51 except:
52 52 return HTTPNotFound()(environ, start_response)
53 53
54 54 #since we wrap into hgweb, just reset the path
55 55 environ['PATH_INFO'] = '/'
56 56 self.baseui = make_ui()
57 57 self.basepath = self.baseui.configitems('paths')[0][1]\
58 58 .replace('*', '')
59 59 self.repo_path = os.path.join(self.basepath, repo_name)
60 60 try:
61 61 app = wsgiapplication(self._make_app)
62 62 except Exception as e:
63 63 return HTTPNotFound()(environ, start_response)
64 64
65 65 """we know that some change was made to repositories and we should
66 66 invalidate the cache to see the changes right away"""
67 67 invalidate_cache('full_changelog', repo_name)
68 68 return app(environ, start_response)
69 69
70 70 def _make_app(self):
71 71 hgserve = hgweb(self.repo_path)
72 72 return self.load_web_settings(hgserve)
73 73
74 74
75 75 def load_web_settings(self, hgserve):
76 76 repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False)
77 77 #set the global ui for hgserve
78 78 hgserve.repo.ui = self.baseui
79 79
80 80 if repoui:
81 81 #set the repository based config
82 82 hgserve.repo.ui = repoui
83 83
84 84 return hgserve
85 85
86 86
@@ -1,121 +1,121 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 4 <head>
5 5 <link rel="icon" href="/images/hgicon.png" type="image/png" />
6 6 <meta name="robots" content="index, nofollow"/>
7 7 <title>${next.title()}</title>
8 8 ##<link rel="stylesheet" href="/js/yui/reset-fonts-grids/reset-fonts-grids.css" type="text/css" />
9 9 ${self.css()}
10 10 ${self.js()}
11 11 </head>
12 12
13 13 <body class="mainbody">
14 14 <div id="container">
15 15 <div class="page-header">
16 16 <h1>${next.breadcrumbs()}</h1>
17 17 ${self.page_nav()}
18 18 </div>
19 19 <div id="main">
20 20 ${next.main()}
21 21 </div>
22 22 <div class="page-footer">
23 Mercurial App &copy; 2010
23 Hg App ${c.hg_app_version} &copy; 2010
24 24 </div>
25 25
26 26 <div id="powered-by">
27 27 <p>
28 28 <a href="http://mercurial.selenic.com/" title="Mercurial">
29 29 <img src="/images/hglogo.png" width="75" height="90" alt="mercurial"/></a>
30 30 </p>
31 31 </div>
32 32
33 33 <div id="corner-top-left"></div>
34 34 <div id="corner-top-right"></div>
35 35 <div id="corner-bottom-left"></div>
36 36 <div id="corner-bottom-right"></div>
37 37
38 38 </div>
39 39 </body>
40 40 </html>
41 41
42 42 ### MAKO DEFS ###
43 43
44 44 <%def name="page_nav()">
45 45 ${self.menu()}
46 46 </%def>
47 47
48 48 <%def name="menu(current)">
49 49 <%
50 50 def is_current(selected):
51 51 if selected == current:
52 52 return 'class=current'
53 53 %>
54 54 %if current not in ['home','admin']:
55 55 <script type="text/javascript">
56 56 YAHOO.util.Event.onDOMReady(function(){
57 57 YAHOO.util.Event.addListener('repo_switcher','click',function(){
58 58 if(YAHOO.util.Dom.hasClass('repo_switcher','selected')){
59 59 YAHOO.util.Dom.setStyle('switch_repos','display','none');
60 60 YAHOO.util.Dom.setStyle('repo_switcher','background','');
61 61 YAHOO.util.Dom.removeClass('repo_switcher','selected');
62 62 }
63 63 else{
64 64 YAHOO.util.Dom.setStyle('switch_repos','display','');
65 65 YAHOO.util.Dom.setStyle('repo_switcher','background','#FFFFFF');
66 66 YAHOO.util.Dom.addClass('repo_switcher','selected');
67 67 }
68 68 });
69 69 YAHOO.util.Event.addListener('repos_list','change',function(e){
70 70 var wa = YAHOO.util.Dom.get('repos_list').value;
71 71
72 72 var url = "${h.url('summary_home',repo_name='__REPLACE__')}".replace('__REPLACE__',wa);
73 73 window.location = url;
74 74 })
75 75 });
76 76 </script>
77 77 <ul class="page-nav">
78 78 <li>
79 79 <a id="repo_switcher" title="${_('Switch repository')}" href="#">&darr;</a>
80 80 <div id="switch_repos" style="display:none;position: absolute;width: 150px;height: 25px">
81 81 <select id="repos_list" size="=10">
82 82 %for repo in c.cached_repo_list:
83 83 <option value="${repo['name']}">${repo['name']}</option>
84 84 %endfor
85 85 </select>
86 86 </div>
87 87 </li>
88 88 <li ${is_current('summary')}>${h.link_to(_('summary'),h.url('summary_home',repo_name=c.repo_name))}</li>
89 89 <li ${is_current('shortlog')}>${h.link_to(_('shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</li>
90 90 <li ${is_current('changelog')}>${h.link_to(_('changelog'),h.url('changelog_home',repo_name=c.repo_name))}</li>
91 91 <li ${is_current('branches')}>${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name))}</li>
92 92 <li ${is_current('tags')}>${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name))}</li>
93 93 <li ${is_current('files')}>${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name))}</li>
94 94 </ul>
95 95 %else:
96 96 <ul class="page-nav">
97 97 <li ${is_current('home')}>${h.link_to(_('Home'),h.url('/'))}</li>
98 98 <li ${is_current('admin')}>${h.link_to(_('Admin'),h.url('admin_home'))}</li>
99 99 <li class="logout">${h.link_to(u'Logout',h.url('logout_home'))}</li>
100 100 </ul>
101 101 %endif
102 102 </%def>
103 103
104 104 <%def name="css()">
105 105 <link rel="stylesheet" href="/css/monoblue_custom.css" type="text/css" />
106 106 </%def>
107 107
108 108 <%def name="js()">
109 109 <script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
110 110 </%def>
111 111
112 112 <!-- DEFINITION OF FORM ERROR FETCHER -->
113 113 <%def name="get_form_error(element)">
114 114 %if hasattr(c,'form_errors') and type(c.form_errors) == dict:
115 115 %if c.form_errors.get(element,False):
116 116 <span class="error-message">
117 117 ${c.form_errors.get(element,'')}
118 118 </span>
119 119 %endif
120 120 %endif
121 121 </%def> No newline at end of file
@@ -1,40 +1,41 b''
1 from pylons_app import get_version
1 2 try:
2 3 from setuptools import setup, find_packages
3 4 except ImportError:
4 5 from ez_setup import use_setuptools
5 6 use_setuptools()
6 7 from setuptools import setup, find_packages
7 8
8 9 setup(
9 10 name='pylons_app',
10 version='1.0',
11 version=get_version(),
11 12 description='',
12 13 author='marcin kuzminski',
13 14 author_email='marcin@python-blog.com',
14 15 url='',
15 16 install_requires=[
16 17 "Pylons>=1.0.0",
17 18 "SQLAlchemy>=0.6",
18 19 "Mako>=0.3.2",
19 20 "vcs>=0.1.1",
20 21 "pygments>=1.3.0"
21 22 ],
22 23 setup_requires=["PasteScript>=1.6.3"],
23 24 packages=find_packages(exclude=['ez_setup']),
24 25 include_package_data=True,
25 26 test_suite='nose.collector',
26 27 package_data={'pylons_app': ['i18n/*/LC_MESSAGES/*.mo']},
27 28 message_extractors={'pylons_app': [
28 29 ('**.py', 'python', None),
29 30 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
30 31 ('public/**', 'ignore', None)]},
31 32 zip_safe=False,
32 33 paster_plugins=['PasteScript', 'Pylons'],
33 34 entry_points="""
34 35 [paste.app_factory]
35 36 main = pylons_app.config.middleware:make_app
36 37
37 38 [paste.app_install]
38 39 main = pylons.util:PylonsInstaller
39 40 """,
40 41 )
General Comments 0
You need to be logged in to leave comments. Login now